#include "onvifToolClass.h"
#include <vector>
#include <json/json.hpp>
#include <thread>
#include "soapStub.h"
#include "wsseapi.h"
#include "soapH.h"
#include "wsdd.nsmap"
#include "jsonOperation.h"

#ifdef WIN32
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")
#else
#include <ifaddrs.h>
#endif

using nlohmann::json;
using std::vector;
using namespace onvif_tool_json_operation;
using namespace std;

onvifTool::onvifTool()
{
    cb_ = nullptr;
}

onvifTool::~onvifTool()
{
    if (UUID != nullptr)
    {
        delete UUID;
        UUID = nullptr;
    }
    listenHelloFlag = 1;
    listenByeFlag = 1;
}

optional<string> onvifTool::init()
{
    setTimeOut();
    string fileName = "onvif_tool_" + utils.getDate() + ".log";
    utils.setLogFileName(fileName.c_str());
    utils.setLogToFile((int)LOG_ERROR, nullptr, 0);
    if (auto err = getIpList(); err)
    {
        string errStr = string("init onvifTool fail: get ipList fail") + *err +
                        string(" can not listen or probe anymore, please solve the issue");
        log(errStr, LOG_CRITICAL);
        return errStr;
    }
    // 使用https的关键代码
    soap_ssl_init();
    UUID = new string(utils.generateUUID());
    return nullopt;
}

void onvifTool::printLog(logCB cb, void *pUserData)
{
    cb_ = cb;
    logUserData = pUserData;
}

// 设置超时时间
void onvifTool::setTimeOut(int timeOut_)
{
    if (timeOut_ <= 0)
    {
        log("setTimeOut fail: timeOut invalid", LOG_ERROR);
        return;
    }
    timeOut = timeOut_;
}

// 监听hello消息
optional<string> onvifTool::listenHello(listenCB cb, void *pUserData)
{
    // 为每个网卡开启一个监听
    for (int i = 0; i < (int)ipList.size(); i++)
    {
        if (auto err = listenHello(cb, pUserData, ipList[i].c_str()); err)
        {
            return *err;
        }
    }
    return nullopt;
}

// 停止hello的监听
optional<string> onvifTool::stopListenHello()
{
    if (listenHelloFlag != 0)
    {
        listenHelloFlag = 1;
        return "never start listen hello or unknown error";
    }
    listenHelloFlag = 1;
    return nullopt;
}

// 监听bye消息
optional<string> onvifTool::listenBye(listenCB cb, void *pUserData)
{
    // 为每个网卡开启一个监听
    for (int i = 0; i < (int)ipList.size(); i++)
    {
        if (auto err = listenBye(cb, pUserData, ipList[i].c_str()); err)
        {
            return *err;
        }
    }
    return nullopt;
}

// 停止bye的监听
optional<string> onvifTool::stopListenBye()
{
    if (listenByeFlag != 0)
    {
        listenByeFlag = 1;
        return "never start listen bye or unknown error";
    }
    listenByeFlag = 1;
    return nullopt;
}

// 设备发现，搜索到的设备以json的形式返回到responseJson里
optional<string> onvifTool::discoverDevice(string &responseJson)
{
    string errPrefix = "discoverDevice error";
    vector<json> deviceList;

    // 遍历每个网卡发送组播消息
    for (int i = 0; i < (int)ipList.size(); i++)
    {
        // 新建soap对象
        soap *soapPtr = newSoap();
        if (soapPtr == nullptr)
        {

            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, "newSoap error");
        }

        // 设置soap的头
        struct SOAP_ENV__Header header;
        soap_default_SOAP_ENV__Header(soapPtr, &header);
        char uuid[80];
        sprintf(uuid, "uuid:%s", UUID->c_str());
        string wsa__To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
        string wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
        header.wsa__MessageID = uuid;
        header.wsa__To = (char *)wsa__To.c_str();
        header.wsa__Action = (char *)wsa__Action.c_str();
        soapPtr->header = &header;

        // 搜索设备的请求体
        struct wsdd__ProbeType probeRequire;
        soap_default_wsdd__ProbeType(soapPtr, &probeRequire);

        // 设置搜索设备类型
        string type = "tdn:NetworkVideoTransmitter";
        probeRequire.Types = (char *)type.c_str();

        // 设置搜索设备范围
        struct wsdd__ScopesType scope;
        soap_default_wsdd__ScopesType(soapPtr, &scope);
        string _item = "onvif://www.onvif.org";
        scope.__item = (char *)_item.c_str();
        probeRequire.Scopes = &scope;

        // 发送探测
        if (soap_send___wsdd__Probe(soapPtr, "soap.udp://239.255.255.250:3702/", nullptr, &probeRequire, (char *)ipList[i].c_str()) == -1)
        {
            string err = printError(soapPtr, errPrefix);
            deleteSoap(soapPtr);
            return err;
        }
        else
        {
            do
            {
                struct __wsdd__ProbeMatches probeResponse;
                // 等待设备回应
                if (soap_recv___wsdd__ProbeMatches(soapPtr, &probeResponse) != 0)
                {
                    break;
                }
                else
                {
                    json device;
                    device["serviceAddress"] = probeResponse.wsdd__ProbeMatches->ProbeMatch->XAddrs ? string(probeResponse.wsdd__ProbeMatches->ProbeMatch->XAddrs) : string("");
                    device["types"] = probeResponse.wsdd__ProbeMatches->ProbeMatch->Types ? string(probeResponse.wsdd__ProbeMatches->ProbeMatch->Types) : string("");
                    device["scopes"] = probeResponse.wsdd__ProbeMatches->ProbeMatch->Scopes ? (probeResponse.wsdd__ProbeMatches->ProbeMatch->Scopes->__item ? string(probeResponse.wsdd__ProbeMatches->ProbeMatch->Scopes->__item) : string("")) : string("");
                    device["endPointAddress"] = probeResponse.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address ? string(probeResponse.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address) : string("");
                    deviceList.push_back(device);
                }
            } while (true);
        }
        deleteSoap(soapPtr);
    }

    json jsonData;
    jsonData["count"] = deviceList.size();
    jsonData["devices"] = deviceList;

    responseJson = jsonData.dump();
    return nullopt;
}

optional<string> onvifTool::getDeviceInformation(string &responseJson,
                                                 const char *deviceXAddr,
                                                 const char *userName,
                                                 const char *password)
{
    string errPrefix = "getDeviceInformation error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetDeviceInformation devInfoRequest;          // 请求
    _tds__GetDeviceInformationResponse devInfoResponse; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetDeviceInformation(soapPtr, deviceXAddr, nullptr, &devInfoRequest, devInfoResponse) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    j["firmwareVersion"] = string(devInfoResponse.FirmwareVersion);
    j["hardwareId"] = string(devInfoResponse.HardwareId);
    j["manufacturer"] = string(devInfoResponse.Manufacturer);
    j["model"] = string(devInfoResponse.Model);
    j["serialNumber"] = string(devInfoResponse.SerialNumber);

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getServiceCapabilities(string &responseJson,
                                                   const char *deviceXAddr)
{
    string errPrefix = "getServiceCapabilities error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    _tds__GetServiceCapabilities request;          // 请求
    _tds__GetServiceCapabilitiesResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetServiceCapabilities(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    buildGetServiceCapabilitiesJsonStr(responseJson, response);
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getServices(string &responseJson,
                                        const char *deviceXAddr)
{
    string errPrefix = "getServices error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    _tds__GetServices getServiceRequest;          // 请求
    _tds__GetServicesResponse getServiceResponse; // 回复

    // 设置请求参数
    getServiceRequest.IncludeCapability = true;

    // 发送请求并接收回复
    if (soap_call___tds__GetServices(soapPtr, deviceXAddr, nullptr, &getServiceRequest, getServiceResponse) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    vector<json> items;
    for (int i = 0; i < getServiceResponse.__sizeService; i++)
    {
        json serviceItem;
        serviceItem["namespace"] = string(getServiceResponse.Service[i]->Namespace);
        serviceItem["serviceAddress"] = string(getServiceResponse.Service[i]->XAddr);
        serviceItem["majorVersion"] = getServiceResponse.Service[i]->Version->Major;
        serviceItem["minorVersion"] = getServiceResponse.Service[i]->Version->Minor;
        items.push_back(serviceItem);
    }

    json j;
    j["count"] = getServiceResponse.__sizeService;
    j["services"] = items;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getDNS(string &responseJson,
                                   const char *deviceXAddr,
                                   const char *userName,
                                   const char *password)
{
    string errPrefix = "getDNS error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetDNS request;          // 请求
    _tds__GetDNSResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetDNS(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    // 是否是动态IP
    j["fromDHCP"] = response.DNSInformation->FromDHCP ? string("true") : string("false");

    vector<string> searchDomain;
    for (int i = 0; i < response.DNSInformation->__sizeSearchDomain; i++)
    {
        searchDomain.push_back(string(response.DNSInformation->SearchDomain[i]));
    }
    j["searchDomain"] = searchDomain;

    // 动态IP
    vector<json> DNSFromDHCP;
    for (int i = 0; i < response.DNSInformation->__sizeDNSFromDHCP; i++)
    {
        json item;
        item["type"] = (response.DNSInformation->DNSFromDHCP[i]->Type == tt__IPType__IPv4) ? "IPv4" : "IPv6";
        item["IPv4Address"] = response.DNSInformation->DNSFromDHCP[i]->IPv4Address ? string(response.DNSInformation->DNSFromDHCP[i]->IPv4Address) : string("");
        item["IPv6Address"] = response.DNSInformation->DNSFromDHCP[i]->IPv6Address ? string(response.DNSInformation->DNSFromDHCP[i]->IPv6Address) : string("");
        DNSFromDHCP.push_back(item);
    }
    j["DNSFromDHCP"] = DNSFromDHCP;

    // 固定IP
    vector<json> DNSManual;
    for (int i = 0; i < response.DNSInformation->__sizeDNSManual; i++)
    {
        json item;
        item["type"] = (response.DNSInformation->DNSManual[i]->Type == tt__IPType__IPv4) ? "IPv4" : "IPv6";
        item["IPv4Address"] = response.DNSInformation->DNSManual[i]->IPv4Address ? string(response.DNSInformation->DNSManual[i]->IPv4Address) : string("");
        item["IPv6Address"] = response.DNSInformation->DNSManual[i]->IPv6Address ? string(response.DNSInformation->DNSManual[i]->IPv6Address) : string("");
        DNSManual.push_back(item);
    }
    j["DNSManual"] = DNSManual;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getDynamicDNS(string &responseJson,
                                          const char *deviceXAddr,
                                          const char *userName,
                                          const char *password)
{
    string errPrefix = "getDynamicDNS error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetDynamicDNS request;          // 请求
    _tds__GetDynamicDNSResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetDynamicDNS(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    switch (response.DynamicDNSInformation->Type)
    {
    case tt__DynamicDNSType__NoUpdate:
        j["type"] = string("NoUpdate");
        break;
    case tt__DynamicDNSType__ClientUpdates:
        j["type"] = string("ClientUpdates");
        break;
    case tt__DynamicDNSType__ServerUpdates:
        j["type"] = string("ServerUpdates");
        break;
    default:
        break;
    }
    j["name"] = response.DynamicDNSInformation->Name ? string(response.DynamicDNSInformation->Name) : string("");
    j["TTL"] = response.DynamicDNSInformation->TTL ? string(response.DynamicDNSInformation->TTL) : string("");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getEndpointReference(string &responseJson,
                                                 const char *deviceXAddr)
{
    string errPrefix = "getEndpointReference error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    _tds__GetEndpointReference request;          // 请求
    _tds__GetEndpointReferenceResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetEndpointReference(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    j["GUID"] = response.GUID ? string(response.GUID) : string("");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getGeoLocation(string &responseJson,
                                           const char *deviceXAddr,
                                           const char *userName,
                                           const char *password)
{
    string errPrefix = "getGeoLocation error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetGeoLocation request;          // 请求
    _tds__GetGeoLocationResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetGeoLocation(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> location;
    for (int i = 0; i < response.__sizeLocation; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseLocationEntity(jsonStr, response.Location[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        location.push_back(json::parse(jsonStr));
    }
    j["location"] = location;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getNetworkDefaultGateway(string &responseJson,
                                                     const char *deviceXAddr,
                                                     const char *userName,
                                                     const char *password)
{
    string errPrefix = "getNetworkDefaultGateway error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetNetworkDefaultGateway request;          // 请求
    _tds__GetNetworkDefaultGatewayResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetNetworkDefaultGateway(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<string> IPv4Addr;
    for (int i = 0; i < response.NetworkGateway->__sizeIPv4Address; i++)
    {
        IPv4Addr.push_back(string(response.NetworkGateway->IPv4Address[i]));
    }
    j["IPv4Address"] = IPv4Addr;

    vector<string> IPv6Addr;
    for (int i = 0; i < response.NetworkGateway->__sizeIPv6Address; i++)
    {
        IPv6Addr.push_back(string(response.NetworkGateway->IPv6Address[i]));
    }
    j["IPv6Address"] = IPv6Addr;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getNetworkInterfaces(string &responseJson,
                                                 const char *deviceXAddr,
                                                 const char *userName,
                                                 const char *password)
{
    string errPrefix = "getNetworkInterfaces error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetNetworkInterfaces request;          // 请求
    _tds__GetNetworkInterfacesResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetNetworkInterfaces(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> interfaces;
    for (int i = 0; i < response.__sizeNetworkInterfaces; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseNetworkInterface(jsonStr, response.NetworkInterfaces[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        interfaces.push_back(json::parse(jsonStr));
    }
    j["interfaces"] = interfaces;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getNetworkProtocols(string &responseJson,
                                                const char *deviceXAddr,
                                                const char *userName,
                                                const char *password)
{
    string errPrefix = "getNetworkProtocols error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetNetworkProtocols request;          // 请求
    _tds__GetNetworkProtocolsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetNetworkProtocols(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> protocols;
    for (int i = 0; i < response.__sizeNetworkProtocols; i++)
    {
        json item;
        switch (response.NetworkProtocols[i]->Name)
        {
        case tt__NetworkProtocolType__HTTP:
            item["name"] = "http";
            break;
        case tt__NetworkProtocolType__HTTPS:
            item["name"] = "https";
            break;
        case tt__NetworkProtocolType__RTSP:
            item["name"] = "rtsp";
            break;
        default:
            break;
        }

        item["enabled"] = response.NetworkProtocols[i]->Enabled ? "true" : "false";

        vector<int> ports;
        for (int i_ = 0; i_ < response.NetworkProtocols[i]->__sizePort; i_++)
        {
            ports.push_back(response.NetworkProtocols[i]->Port[i_]);
        }
        item["ports"] = ports;

        protocols.push_back(item);
    }
    j["protocols"] = protocols;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getHostname(string &responseJson,
                                        const char *deviceXAddr)
{
    string errPrefix = "getHostname error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    _tds__GetHostname request;          // 请求
    _tds__GetHostnameResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetHostname(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    j["name"] = response.HostnameInformation->Name ? string(response.HostnameInformation->Name) : string("");
    j["fromDHCP"] = response.HostnameInformation->FromDHCP ? string("true") : string("false");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getRemoteUser(string &responseJson,
                                          const char *deviceXAddr,
                                          const char *userName,
                                          const char *password)
{
    string errPrefix = "getRemoteUser error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetRemoteUser request;          // 请求
    _tds__GetRemoteUserResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetRemoteUser(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    if (response.RemoteUser != nullptr)
    {
        j["username"] = response.RemoteUser->Username ? string(response.RemoteUser->Username) : string("");
        j["password"] = response.RemoteUser->Password ? string(response.RemoteUser->Password) : string("");
        j["useDerivedPassword"] = response.RemoteUser->UseDerivedPassword ? string("true") : string("false");
    }

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getScopes(string &responseJson,
                                      const char *deviceXAddr,
                                      const char *userName,
                                      const char *password)
{
    string errPrefix = "getScopes error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetScopes request;          // 请求
    _tds__GetScopesResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetScopes(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> scopes;
    for (int i = 0; i < response.__sizeScopes; i++)
    {
        json item;
        item["scopeDef"] = response.Scopes[i]->ScopeDef == tt__ScopeDefinition__Fixed ? string("fixed") : string("configurable");
        item["scopeItem"] = response.Scopes[i]->ScopeItem ? string(response.Scopes[i]->ScopeItem) : string("");
        scopes.push_back(item);
    }
    j["scopes"] = scopes;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

// 获取onvif用户
optional<string> onvifTool::getUsers(string &responseJson,
                                     const char *deviceXAddr,
                                     const char *userName,
                                     const char *password)
{
    string errPrefix = "getUsers error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetUsers request;          // 请求
    _tds__GetUsersResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetUsers(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> users;
    for (int i = 0; i < response.__sizeUser; i++)
    {
        json item;
        item["userName"] = response.User[i]->Username ? string(response.User[i]->Username) : string("");
        item["password"] = response.User[i]->Password ? string(response.User[i]->Password) : string("");
        switch (response.User[i]->UserLevel)
        {
        case tt__UserLevel__Administrator:
            item["userLevel"] = "administrator";
            break;
        case tt__UserLevel__Operator:
            item["userLevel"] = "operator";
            break;
        case tt__UserLevel__User:
            item["userLevel"] = "user";
            break;
        case tt__UserLevel__Anonymous:
            item["userLevel"] = "anonymous";
            break;
        case tt__UserLevel__Extended:
            item["userLevel"] = "extended";
            break;
        default:
            break;
        }
        users.push_back(item);
    }
    j["user"] = users;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getWsdlUrl(string &responseJson,
                                       const char *deviceXAddr)
{
    string errPrefix = "getWsdlUrl error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    _tds__GetWsdlUrl request;          // 请求
    _tds__GetWsdlUrlResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetWsdlUrl(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    j["wsdlUrl"] = response.WsdlUrl ? string(response.WsdlUrl) : string("");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getDiscoveryMode(string &responseJson,
                                             const char *deviceXAddr,
                                             const char *userName,
                                             const char *password)
{
    string errPrefix = "getDiscoveryMode error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetDiscoveryMode request;          // 请求
    _tds__GetDiscoveryModeResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetDiscoveryMode(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    j["discoverable"] = response.DiscoveryMode == tt__DiscoveryMode__Discoverable ? "true" : "false";

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getRemoteDiscoveryMode(string &responseJson,
                                                   const char *deviceXAddr,
                                                   const char *userName,
                                                   const char *password)
{
    string errPrefix = "getRemoteDiscoveryMode error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__GetRemoteDiscoveryMode request;          // 请求
    _tds__GetRemoteDiscoveryModeResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__GetRemoteDiscoveryMode(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    j["discoverable"] = response.RemoteDiscoveryMode == tt__DiscoveryMode__Discoverable ? "true" : "false";

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setDNS(string &responseJson,
                                   const char *deviceXAddr,
                                   const char *userName,
                                   const char *password,
                                   ONVIF_SET_DNS_PARAM *param)
{
    string errPrefix = "setDNS error";

    // 判断参数是否有效
    if (param == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    if ((param->sizeSearchDomain > 0 && param->searchDomain == nullptr) ||
        (param->sizeDNSManual > 0 && param->DNSManual == nullptr))
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetDNS request;          // 请求
    _tds__SetDNSResponse response; // 回复

    // 设置请求参数
    request.FromDHCP = param->useDHCP;
    request.__sizeDNSManual = param->sizeDNSManual;
    request.__sizeSearchDomain = param->sizeSearchDomain;
    request.SearchDomain = param->searchDomain;

    tt__IPAddress **ipAddr = nullptr;
    if (param->sizeDNSManual > 0)
    {

        ipAddr = new tt__IPAddress *[param->sizeDNSManual];
        for (int i = 0; i < param->sizeDNSManual; i++)
        {
            ipAddr[i] = new tt__IPAddress();
            ipAddr[i]->Type = param->DNSManual[i]->IPv4Type ? tt__IPType__IPv4 : tt__IPType__IPv6;
            ipAddr[i]->IPv4Address = param->DNSManual[i]->IPv4Address;
            ipAddr[i]->IPv6Address = param->DNSManual[i]->IPv6Address;
        }
    }
    request.DNSManual = ipAddr;

    // 发送请求并接收回复
    if (soap_call___tds__SetDNS(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        if (param->sizeDNSManual > 0)
        {
            for (int i = 0; i < param->sizeDNSManual; i++)
            {
                delete ipAddr[i];
            }
            delete ipAddr;
            ipAddr = nullptr;
        }
        deleteSoap(soapPtr);
        return err;
    }

    if (param->sizeDNSManual > 0)
    {
        for (int i = 0; i < param->sizeDNSManual; i++)
        {
            delete ipAddr[i];
        }
        delete ipAddr;
        ipAddr = nullptr;
    }
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setDynamicDNS(string &responseJson,
                                          const char *deviceXAddr,
                                          const char *userName,
                                          const char *password,
                                          ONVIF_SET_DYNAMIC_DNS_PARAM *param)
{
    string errPrefix = "setDynamicDNS error";

    // 判断参数是否有效
    if (param == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetDynamicDNS request;          // 请求
    _tds__SetDynamicDNSResponse response; // 回复

    // 设置请求参数
    if (param->name != nullptr)
    {
        request.Name = param->name;
    }

    if (param->type != nullptr)
    {
        switch (*param->type)
        {
        case 0:
            request.Type = tt__DynamicDNSType__NoUpdate;
            break;
        case 1:
            request.Type = tt__DynamicDNSType__ClientUpdates;
            break;
        case 2:
            request.Type = tt__DynamicDNSType__ServerUpdates;
            break;

        default:
            break;
        }
    }

    if (param->TTL != nullptr)
    {
        request.TTL = param->TTL;
    }

    // 发送请求并接收回复
    if (soap_call___tds__SetDynamicDNS(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setHostname(string &responseJson,
                                        const char *deviceXAddr,
                                        const char *userName,
                                        const char *password,
                                        const char *name)
{
    string errPrefix = "SetHostname error";

    // 判断参数是否有效
    if (name == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetHostname request;          // 请求
    _tds__SetHostnameResponse response; // 回复

    // 设置请求参数
    request.Name = (char *)name;

    // 发送请求并接收回复
    if (soap_call___tds__SetHostname(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::systemReboot(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password)
{
    string errPrefix = "systemReboot error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SystemReboot request;          // 请求
    _tds__SystemRebootResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tds__SystemReboot(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    json j;
    j["message"] = response.Message ? string(response.Message) : string("");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setHostnameFromDHCP(string &responseJson,
                                                const char *deviceXAddr,
                                                const char *userName,
                                                const char *password,
                                                bool useDHCP)
{
    string errPrefix = "setHostnameFromDHCP error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetHostnameFromDHCP request;          // 请求
    _tds__SetHostnameFromDHCPResponse response; // 回复

    // 设置请求参数
    request.FromDHCP = useDHCP;

    // 发送请求并接收回复
    if (soap_call___tds__SetHostnameFromDHCP(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    json j;
    j["rebootNeeded"] = response.RebootNeeded ? string("true") : string("false");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setUser(string &responseJson,
                                    const char *deviceXAddr,
                                    const char *userName,
                                    const char *password,
                                    ONVIF_SET_USER_PARAM *param)
{
    string errPrefix = "setUser error";

    // 判断参数是否有效
    if (param == nullptr || param->sizeUser <= 0 || param->users == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetUser request;          // 请求
    _tds__SetUserResponse response; // 回复

    // 设置请求参数
    request.__sizeUser = param->sizeUser;

    tt__User **users = nullptr;
    users = new tt__User *[param->sizeUser];
    for (int i = 0; i < param->sizeUser; i++)
    {
        users[i] = new tt__User;
        users[i]->Username = param->users[i].userName;
        users[i]->Password = param->users[i].password;
        if (param->users[i].userLevel != nullptr)
        {
            switch (*param->users[i].userLevel)
            {
            case 0:
                users[i]->UserLevel = tt__UserLevel__Administrator;
                break;
            case 1:
                users[i]->UserLevel = tt__UserLevel__Operator;
                break;
            case 2:
                users[i]->UserLevel = tt__UserLevel__User;
                break;
            case 3:
                users[i]->UserLevel = tt__UserLevel__Anonymous;
                break;
            case 4:
                users[i]->UserLevel = tt__UserLevel__Extended;
                break;

            default:
                break;
            }
        }
    }

    request.User = users;

    // 发送请求并接收回复
    if (soap_call___tds__SetUser(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        for (int i = 0; i < param->sizeUser; i++)
        {
            delete users[i];
        }
        delete[] users;
        users = nullptr;
        deleteSoap(soapPtr);
        return err;
    }

    for (int i = 0; i < param->sizeUser; i++)
    {
        delete users[i];
    }
    delete[] users;
    users = nullptr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setScopes(string &responseJson,
                                      const char *deviceXAddr,
                                      const char *userName,
                                      const char *password,
                                      ONVIF_SET_SCOPES_PARAM *param)
{
    string errPrefix = "setScopes error";

    // 判断参数是否有效
    if (param == nullptr || param->sizeScopes < 0)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetScopes request;          // 请求
    _tds__SetScopesResponse response; // 回复

    // 设置请求参数
    request.__sizeScopes = param->sizeScopes;
    request.Scopes = param->scopes;

    // 发送请求并接收回复
    if (soap_call___tds__SetScopes(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setRemoteUser(string &responseJson,
                                          const char *deviceXAddr,
                                          const char *userName,
                                          const char *password,
                                          ONVIF_SET_REMOTE_USER_PARAM *param)
{
    string errPrefix = "setRemoteUser error";

    // 判断参数是否有效
    if (param == nullptr || userName == nullptr || password == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetRemoteUser request;          // 请求
    _tds__SetRemoteUserResponse response; // 回复

    // 设置请求参数
    tt__RemoteUser remoteUser;
    remoteUser.Password = param->password;
    remoteUser.Username = param->userName;
    remoteUser.UseDerivedPassword = param->useDerivedPassword;

    request.RemoteUser = &remoteUser;

    // 发送请求并接收回复
    if (soap_call___tds__SetRemoteUser(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setDiscoveryMode(string &responseJson,
                                             const char *deviceXAddr,
                                             const char *userName,
                                             const char *password,
                                             bool enable)
{
    string errPrefix = "setDiscoveryMode error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetDiscoveryMode request;          // 请求
    _tds__SetDiscoveryModeResponse response; // 回复

    // 设置请求参数
    if (enable)
    {
        request.DiscoveryMode = tt__DiscoveryMode__Discoverable;
    }
    else
    {
        request.DiscoveryMode = tt__DiscoveryMode__NonDiscoverable;
    }

    // 发送请求并接收回复
    if (soap_call___tds__SetDiscoveryMode(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setRemoteDiscoveryMode(string &responseJson,
                                                   const char *deviceXAddr,
                                                   const char *userName,
                                                   const char *password,
                                                   bool enable)
{
    string errPrefix = "setRemoteDiscoveryMode error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetRemoteDiscoveryMode request;          // 请求
    _tds__SetRemoteDiscoveryModeResponse response; // 回复

    // 设置请求参数
    if (enable)
    {
        request.RemoteDiscoveryMode = tt__DiscoveryMode__Discoverable;
    }
    else
    {
        request.RemoteDiscoveryMode = tt__DiscoveryMode__NonDiscoverable;
    }

    // 发送请求并接收回复
    if (soap_call___tds__SetRemoteDiscoveryMode(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setNetworkDefaultGateway(string &responseJson,
                                                     const char *deviceXAddr,
                                                     const char *userName,
                                                     const char *password,
                                                     ONVIF_SET_NETWORK_DEFAULT_GATEWAY_PARAM *param)
{
    string errPrefix = "setNetworkDefaultGateway error";

    // 判断参数是否有效
    if (param == nullptr ||
        (param->sizeIPv4 > 0 && param->IPv4Address == nullptr) ||
        (param->sizeIPv6 > 0 && param->IPv6Address == nullptr))
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetNetworkDefaultGateway request;          // 请求
    _tds__SetNetworkDefaultGatewayResponse response; // 回复

    // 设置请求参数
    request.__sizeIPv4Address = (int)param->sizeIPv4;
    request.IPv4Address = param->IPv4Address;
    request.__sizeIPv6Address = (int)param->sizeIPv6;
    request.IPv6Address = param->IPv6Address;

    // 发送请求并接收回复
    if (soap_call___tds__SetNetworkDefaultGateway(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setNetworkInterfaces(string &responseJson,
                                                 const char *deviceXAddr,
                                                 const char *userName,
                                                 const char *password,
                                                 ONVIF_SET_NETWORK_INTERFACE_PARAM *param)
{
    string errPrefix = "setNetworkInterfaces error";

    // 判断参数是否有效
    if (param == nullptr || param->interfaceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetNetworkInterfaces request;          // 请求
    _tds__SetNetworkInterfacesResponse response; // 回复

    // 设置请求参数
    request.InterfaceToken = param->interfaceToken;
    tt__NetworkInterfaceSetConfiguration networkInterface;

    if (auto err = jsonOperation::buildNetworkInterfaceSetConfiguration(networkInterface, param); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    request.NetworkInterface = &networkInterface;

    // 发送请求并接收回复
    if (soap_call___tds__SetNetworkInterfaces(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        jsonOperation::deleteNetworkInterfaceSetConfiguration(&networkInterface);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    j["rebootNeeded"] = response.RebootNeeded ? string("true") : string("false");

    responseJson = j.dump();
    jsonOperation::deleteNetworkInterfaceSetConfiguration(&networkInterface);
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setNetworkProtocols(string &responseJson,
                                                const char *deviceXAddr,
                                                const char *userName,
                                                const char *password,
                                                ONVIF_SET_NETWORK_PROTOCOLS_PARAM *param)
{
    string errPrefix = "setNetworkProtocols error";

    // 判断参数是否有效
    if (param == nullptr || param->sizeProtocols <= 0 || param->protocols == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tds__SetNetworkProtocols request;          // 请求
    _tds__SetNetworkProtocolsResponse response; // 回复

    // 设置请求参数
    request.__sizeNetworkProtocols = param->sizeProtocols;
    request.NetworkProtocols = new tt__NetworkProtocol *[param->sizeProtocols];
    tt__NetworkProtocol **protocols = request.NetworkProtocols;

    for (int i = 0; i < param->sizeProtocols; i++)
    {
        protocols[i] = new tt__NetworkProtocol;
        switch (param->protocols[i]->protocolsName)
        {
        case 0:
            protocols[i]->Name = tt__NetworkProtocolType__HTTP;
            break;
        case 1:
            protocols[i]->Name = tt__NetworkProtocolType__HTTPS;
            break;
        case 2:
            protocols[i]->Name = tt__NetworkProtocolType__RTSP;
            break;

        default:
            for (int ii = 0; ii <= i; ii++)
            {
                delete protocols[ii];
            }
            delete[] protocols;
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, "param error");
        }
        protocols[i]->Enabled = param->protocols[i]->enabled;
        protocols[i]->__sizePort = param->protocols[i]->sizePort;
        if (param->protocols[i]->sizePort < 0 ||
            (param->protocols[i]->sizePort > 0 && param->protocols[i]->port == nullptr))
        {
            for (int ii = 0; ii <= i; ii++)
            {
                delete protocols[ii];
            }
            delete[] protocols;
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, "param error");
        }
        protocols[i]->Port = param->protocols[i]->port;
    }

    // 发送请求并接收回复
    if (soap_call___tds__SetNetworkProtocols(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        for (int i = 0; i < param->sizeProtocols; i++)
        {
            delete protocols[i];
        }
        delete[] protocols;
        deleteSoap(soapPtr);
        return err;
    }

    for (int i = 0; i < param->sizeProtocols; i++)
    {
        delete protocols[i];
    }
    delete[] protocols;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSources_V1(string &responseJson,
                                               const char *deviceXAddr,
                                               const char *userName,
                                               const char *password)
{
    string errPrefix = "getVideoSources_V1 error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoSources request;          // 请求
    _trt__GetVideoSourcesResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoSources(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> videoSources;
    for (int i = 0; i < response.__sizeVideoSources; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseVideoSource(jsonStr, response.VideoSources[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(jsonStr);
        videoSources.push_back(item);
    }
    j["count"] = response.__sizeVideoSources;
    j["videoSources"] = videoSources;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSourceConfigurations_V1(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password)
{
    string errPrefix = "getVideoSourceConfigurations_V1 error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoSourceConfigurations request;          // 请求
    _trt__GetVideoSourceConfigurationsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoSourceConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {
        string jsonStr;

        if (auto err = jsonOperation::parseVideoSourceConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(jsonStr);

        configurations.push_back(item);
    }

    json j;
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSourceConfiguration_V1(string &responseJson,
                                                           const char *deviceXAddr,
                                                           const char *userName,
                                                           const char *password,
                                                           const char *configurationToken)
{
    string errPrefix = "getVideoSourceConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoSourceConfiguration request;          // 请求
    _trt__GetVideoSourceConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoSourceConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里

    string jsonStr;

    if (auto err = jsonOperation::parseVideoSourceConfiguration(jsonStr, response.Configuration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSourceConfigurationOptions_V1(string &responseJson,
                                                                  const char *deviceXAddr,
                                                                  const char *userName,
                                                                  const char *password,
                                                                  const char *configurationToken,
                                                                  const char *profileToken)
{
    string errPrefix = "getVideoSourceConfigurationOptions_V1 error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoSourceConfigurationOptions request;          // 请求
    _trt__GetVideoSourceConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoSourceConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里

    string jsonStr;

    if (auto err = jsonOperation::parseVideoSourceConfigurationOptions(jsonStr, response.Options); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSourceModes_V1(string &responseJson,
                                                   const char *deviceXAddr,
                                                   const char *userName,
                                                   const char *password,
                                                   const char *videoSourceToken)
{
    string errPrefix = "getVideoSourceModes_V1 error";

    // 判断参数是否有效
    if (videoSourceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoSourceModes request;          // 请求
    _trt__GetVideoSourceModesResponse response; // 回复

    // 设置请求参数
    request.VideoSourceToken = (char *)videoSourceToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoSourceModes(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> videoSourceModes;
    for (int i = 0; i < response.__sizeVideoSourceModes; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseVideoSourceMode_V1(jsonStr, response.VideoSourceModes[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(jsonStr);
        videoSourceModes.push_back(item);
    }
    j["count"] = response.__sizeVideoSourceModes;
    j["videoSourceModes"] = videoSourceModes;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoEncoderConfigurations_V1(string &responseJson,
                                                             const char *deviceXAddr,
                                                             const char *userName,
                                                             const char *password)
{
    string errPrefix = "getVideoEncoderConfigurations_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoEncoderConfigurations request;          // 请求
    _trt__GetVideoEncoderConfigurationsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoEncoderConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseVideoEncoderConfiguration_V1(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoEncoderConfiguration_V1(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password,
                                                            const char *configurationToken)
{
    string errPrefix = "getVideoEncoderConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoEncoderConfiguration request;          // 请求
    _trt__GetVideoEncoderConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoEncoderConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里

    string jsonStr;
    if (auto err = jsonOperation::parseVideoEncoderConfiguration_V1(jsonStr, response.Configuration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoEncoderConfigurationOptions_V1(string &responseJson,
                                                                   const char *deviceXAddr,
                                                                   const char *userName,
                                                                   const char *password,
                                                                   const char *configurationToken,
                                                                   const char *profileToken)
{
    string errPrefix = "getVideoEncoderConfigurationOptions_V1 error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoEncoderConfigurationOptions request;          // 请求
    _trt__GetVideoEncoderConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoEncoderConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里

    string jsonStr;

    if (auto err = jsonOperation::parseVideoEncoderConfigurationOptions_V1(jsonStr, response.Options); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioSources_V1(string &responseJson,
                                               const char *deviceXAddr,
                                               const char *userName,
                                               const char *password)
{
    string errPrefix = "getAudioSources_V1 error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioSources request;          // 请求
    _trt__GetAudioSourcesResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioSources(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> audioSources;

    for (int i = 0; i < response.__sizeAudioSources; i++)
    {
        json item;

        item["token"] = response.AudioSources[i]->token ? string(response.AudioSources[i]->token) : string("");
        item["channels"] = to_string(response.AudioSources[i]->Channels);

        audioSources.push_back(item);
    }

    j["count"] = response.__sizeAudioSources;
    j["audioSources"] = audioSources;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioSourceConfigurations_V1(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password)
{
    string errPrefix = "getAudioSourceConfigurations_V1 error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioSourceConfigurations request;          // 请求
    _trt__GetAudioSourceConfigurationsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioSourceConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> configurations;

    for (int i = 0; i < response.__sizeConfigurations; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseAudioSourceConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }

    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioSourceConfiguration_V1(string &responseJson,
                                                           const char *deviceXAddr,
                                                           const char *userName,
                                                           const char *password,
                                                           const char *configurationToken)
{
    string errPrefix = "getAudioSourceConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioSourceConfiguration request;          // 请求
    _trt__GetAudioSourceConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioSourceConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioSourceConfiguration(jsonStr, response.Configuration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioSourceConfigurationOptions_V1(string &responseJson,
                                                                  const char *deviceXAddr,
                                                                  const char *userName,
                                                                  const char *password,
                                                                  const char *configurationToken,
                                                                  const char *profileToken)
{
    string errPrefix = "getAudioSourceConfigurationOptions_V1 error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioSourceConfigurationOptions request;          // 请求
    _trt__GetAudioSourceConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioSourceConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<string> inputTokensAvailable;
    for (int i = 0; i < response.Options->__sizeInputTokensAvailable; i++)
    {
        inputTokensAvailable.push_back(string(response.Options->InputTokensAvailable[i]));
    }
    j["count"] = response.Options->__sizeInputTokensAvailable;
    j["inputTokensAvailable"] = inputTokensAvailable;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioOutputs_V1(string &responseJson,
                                               const char *deviceXAddr,
                                               const char *userName,
                                               const char *password)
{
    string errPrefix = "getAudioOutputs_V1 error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioOutputs request;          // 请求
    _trt__GetAudioOutputsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioOutputs(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<string> audioOutputs;

    for (int i = 0; i < response.__sizeAudioOutputs; i++)
    {
        audioOutputs.push_back(string(response.AudioOutputs[i]->token));
    }

    j["count"] = response.__sizeAudioOutputs;
    j["audioOutputs"] = audioOutputs;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioOutputConfigurations_V1(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password)
{
    string errPrefix = "getAudioOutputConfigurations_V1 error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioOutputConfigurations request;          // 请求
    _trt__GetAudioOutputConfigurationsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioOutputConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> configurations;

    for (int i = 0; i < response.__sizeConfigurations; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseAudioOutputConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }

    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioOutputConfiguration_V1(string &responseJson,
                                                           const char *deviceXAddr,
                                                           const char *userName,
                                                           const char *password,
                                                           const char *configurationToken)
{
    string errPrefix = "getAudioOutputConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioOutputConfiguration request;          // 请求
    _trt__GetAudioOutputConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioOutputConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioOutputConfiguration(jsonStr, response.Configuration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioOutputConfigurationOptions_V1(string &responseJson,
                                                                  const char *deviceXAddr,
                                                                  const char *userName,
                                                                  const char *password,
                                                                  const char *configurationToken,
                                                                  const char *profileToken)
{
    string errPrefix = "getAudioOutputConfigurationOptions_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioOutputConfigurationOptions request;          // 请求
    _trt__GetAudioOutputConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioOutputConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioOutputConfigurationOptions(jsonStr, response.Options); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioEncoderConfigurations_V1(string &responseJson,
                                                             const char *deviceXAddr,
                                                             const char *userName,
                                                             const char *password)
{
    string errPrefix = "getAudioEncoderConfigurations_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioEncoderConfigurations request;          // 请求
    _trt__GetAudioEncoderConfigurationsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioEncoderConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseAudioEncoderConfiguration_V1(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }

    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioEncoderConfiguration_V1(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password,
                                                            const char *configurationToken)
{
    string errPrefix = "getAudioEncoderConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioEncoderConfiguration request;          // 请求
    _trt__GetAudioEncoderConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioEncoderConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioEncoderConfiguration_V1(jsonStr, response.Configuration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioEncoderConfigurationOptions_V1(string &responseJson,
                                                                   const char *deviceXAddr,
                                                                   const char *userName,
                                                                   const char *password,
                                                                   const char *configurationToken,
                                                                   const char *profileToken)
{
    string errPrefix = "getAudioEncoderConfigurationOptions_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioEncoderConfigurationOptions request;          // 请求
    _trt__GetAudioEncoderConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioEncoderConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioEncoderConfigurationOptions(jsonStr, response.Options); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioDecoderConfigurations_V1(string &responseJson,
                                                             const char *deviceXAddr,
                                                             const char *userName,
                                                             const char *password)
{
    string errPrefix = "getAudioDecoderConfigurations_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioDecoderConfigurations request;          // 请求
    _trt__GetAudioDecoderConfigurationsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioDecoderConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseAudioDecoderConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioDecoderConfiguration_V1(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password,
                                                            const char *configurationToken)
{
    string errPrefix = "getAudioDecoderConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioDecoderConfiguration request;          // 请求
    _trt__GetAudioDecoderConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioDecoderConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioDecoderConfiguration(jsonStr, response.Configuration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioDecoderConfigurationOptions_V1(string &responseJson,
                                                                   const char *deviceXAddr,
                                                                   const char *userName,
                                                                   const char *password,
                                                                   const char *configurationToken,
                                                                   const char *profileToken)
{
    string errPrefix = "getAudioDecoderConfigurationOptions_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetAudioDecoderConfigurationOptions request;          // 请求
    _trt__GetAudioDecoderConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetAudioDecoderConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioDecoderConfigurationOptions_V1(jsonStr, response.Options); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getMetadataConfigurations_V1(string &responseJson,
                                                         const char *deviceXAddr,
                                                         const char *userName,
                                                         const char *password)
{
    string errPrefix = "getMetadataConfigurations_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetMetadataConfigurations request;          // 请求
    _trt__GetMetadataConfigurationsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetMetadataConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseMetadataConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getMetadataConfiguration_V1(string &responseJson,
                                                        const char *deviceXAddr,
                                                        const char *userName,
                                                        const char *password,
                                                        const char *configurationToken)
{
    string errPrefix = "getMetadataConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetMetadataConfiguration request;          // 请求
    _trt__GetMetadataConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetMetadataConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseMetadataConfiguration(jsonStr, response.Configuration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getMetadataConfigurationOptions_V1(string &responseJson,
                                                               const char *deviceXAddr,
                                                               const char *userName,
                                                               const char *password,
                                                               const char *configurationToken,
                                                               const char *profileToken)
{
    string errPrefix = "getMetadataConfigurationOptions_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetMetadataConfigurationOptions request;          // 请求
    _trt__GetMetadataConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetMetadataConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseMetadataConfigurationOptions(jsonStr, response.Options); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoAnalyticsConfigurations_V1(string &responseJson,
                                                               const char *deviceXAddr,
                                                               const char *userName,
                                                               const char *password)
{
    string errPrefix = "getVideoAnalyticsConfigurations_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoAnalyticsConfigurations request;          // 请求
    _trt__GetVideoAnalyticsConfigurationsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoAnalyticsConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseVideoAnalyticsConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoAnalyticsConfiguration_V1(string &responseJson,
                                                              const char *deviceXAddr,
                                                              const char *userName,
                                                              const char *password,
                                                              const char *configurationToken)
{
    string errPrefix = "getVideoAnalyticsConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetVideoAnalyticsConfiguration request;          // 请求
    _trt__GetVideoAnalyticsConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetVideoAnalyticsConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseVideoAnalyticsConfiguration(jsonStr, response.Configuration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getProfiles_V1(string &responseJson,
                                           const char *deviceXAddr,
                                           const char *userName,
                                           const char *password)
{
    string errPrefix = "getProfiles_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetProfiles request;          // 请求
    _trt__GetProfilesResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___trt__GetProfiles(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> profiles;
    for (int i = 0; i < response.__sizeProfiles; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseProfiles_V1(jsonStr, response.Profiles[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        profiles.push_back(item);
    }
    j["count"] = response.__sizeProfiles;
    j["profiles"] = profiles;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getProfile_V1(string &responseJson,
                                          const char *deviceXAddr,
                                          const char *userName,
                                          const char *password,
                                          const char *profileToken)
{
    string errPrefix = "getProfile_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetProfile request;          // 请求
    _trt__GetProfileResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetProfile(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseProfiles_V1(jsonStr, response.Profile); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::createProfile_V1(string &responseJson,
                                             const char *deviceXAddr,
                                             const char *userName,
                                             const char *password,
                                             const char *name,
                                             const char *profileToken)
{
    string errPrefix = "createProfile_V1 error";

    // 判断参数是否有效
    if (name == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__CreateProfile request;          // 请求
    _trt__CreateProfileResponse response; // 回复

    // 设置请求参数
    request.Name = (char *)name;
    request.Token = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__CreateProfile(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseProfiles_V1(jsonStr, response.Profile); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::deleteProfile_V1(string &responseJson,
                                             const char *deviceXAddr,
                                             const char *userName,
                                             const char *password,
                                             const char *profileToken)
{
    string errPrefix = "deleteProfile_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__DeleteProfile request;          // 请求
    _trt__DeleteProfileResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__DeleteProfile(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getOSDs_V1(string &responseJson,
                                       const char *deviceXAddr,
                                       const char *userName,
                                       const char *password,
                                       const char *videoSourceConfigurationToken)
{
    string errPrefix = "getOSDs_V1 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetOSDs request;          // 请求
    _trt__GetOSDsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)videoSourceConfigurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetOSDs(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> OSDs;
    for (int i = 0; i < response.__sizeOSDs; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseOSD(jsonStr, response.OSDs[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(jsonStr);
        OSDs.push_back(item);
    }
    j["count"] = response.__sizeOSDs;
    j["OSDs"] = OSDs;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getOSD_V1(string &responseJson,
                                      const char *deviceXAddr,
                                      const char *userName,
                                      const char *password,
                                      const char *configurationToken)
{
    string errPrefix = "getOSD_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetOSD request;          // 请求
    _trt__GetOSDResponse response; // 回复

    // 设置请求参数
    request.OSDToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetOSD(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseOSD(jsonStr, response.OSD); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getOSDOptions_V1(string &responseJson,
                                             const char *deviceXAddr,
                                             const char *userName,
                                             const char *password,
                                             const char *videoSourceConfigurationToken)
{
    string errPrefix = "getOSDOptions_V1 error";

    // 判断参数是否有效
    if (videoSourceConfigurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetOSDOptions request;          // 请求
    _trt__GetOSDOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)videoSourceConfigurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetOSDOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseOSDOptions(jsonStr, response.OSDOptions); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::createOSD_V1(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password,
                                         ONVIF_SET_OSD_PARAM *param)
{
    string errPrefix = "createOSD_V1 error";

    // 判断参数是否有效
    if (param == nullptr || param->OSDConfigurationToken == nullptr || param->videoSourceConfigurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__CreateOSD request;          // 请求
    _trt__CreateOSDResponse response; // 回复

    // 设置请求参数
    tt__OSDConfiguration OSD;
    if (auto err = jsonOperation::buildOSDConfiguration(OSD, param); err)
    {
        jsonOperation::deleteOSDConfiguration(&OSD);
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }
    request.OSD = &OSD;

    // 发送请求并接收回复
    if (soap_call___trt__CreateOSD(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        jsonOperation::deleteOSDConfiguration(&OSD);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析返回内容
    json j;
    j["OSDToken"] = response.OSDToken ? string(response.OSDToken) : string("");

    responseJson = j.dump();
    jsonOperation::deleteOSDConfiguration(&OSD);
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::deleteOSD_V1(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password,
                                         const char *configurationToken)
{
    string errPrefix = "deleteOSD_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__DeleteOSD request;          // 请求
    _trt__DeleteOSDResponse response; // 回复

    // 设置请求参数
    request.OSDToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___trt__DeleteOSD(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setOSD_V1(string &responseJson,
                                      const char *deviceXAddr,
                                      const char *userName,
                                      const char *password,
                                      ONVIF_SET_OSD_PARAM *param)
{
    string errPrefix = "setOSD_V1 error";

    // 判断参数是否有效
    if (param == nullptr || param->OSDConfigurationToken == nullptr || param->videoSourceConfigurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__SetOSD request;          // 请求
    _trt__SetOSDResponse response; // 回复

    // 设置请求参数
    tt__OSDConfiguration OSD;
    if (auto err = jsonOperation::buildOSDConfiguration(OSD, param); err)
    {
        jsonOperation::deleteOSDConfiguration(&OSD);
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }
    request.OSD = &OSD;

    // 发送请求并接收回复
    if (soap_call___trt__SetOSD(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        jsonOperation::deleteOSDConfiguration(&OSD);
        deleteSoap(soapPtr);
        return err;
    }

    jsonOperation::deleteOSDConfiguration(&OSD);
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getStreamUri_V1(string &responseJson,
                                            const char *deviceXAddr,
                                            const char *userName,
                                            const char *password,
                                            const char *profileToken,
                                            ONVIF_STREAM_SETUP_PARAM *streamSetup)
{
    string errPrefix = "getStreamUri_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr || streamSetup == nullptr || streamSetup->streamType > 1 || streamSetup->transport.protocolsName > 3)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetStreamUri request;          // 请求
    _trt__GetStreamUriResponse response; // 回复

    // 定义一个函数用来递归生成tt__Transport
    auto fun = [](tt__Transport *transport, ONVIF_TRANSPORT_PROTOCOL *param, auto &&self) -> void
    {
        switch (param->protocolsName)
        {
        case 0:
            transport->Protocol = tt__TransportProtocol__UDP;
            break;
        case 1:
            transport->Protocol = tt__TransportProtocol__TCP;
            break;
        case 2:
            transport->Protocol = tt__TransportProtocol__RTSP;
            break;
        case 3:
            transport->Protocol = tt__TransportProtocol__HTTP;
            break;
        default:
            break;
        }

        transport->Tunnel = nullptr;
        if (param->tunnel == nullptr)
        {
            return;
        }

        transport->Tunnel = new tt__Transport;
        self(transport->Tunnel, param->tunnel, self);
    };

    // 定义一个函数用来释放tt__Transport
    auto deleteFun = [](tt__Transport *transport, auto &&self) -> void
    {
        if (transport == nullptr)
        {
            return;
        }

        if (transport->Tunnel != nullptr)
        {
            self(transport->Tunnel, self);
            transport->Tunnel = nullptr;
        }

        delete transport;
        transport = nullptr;
    };

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    tt__StreamSetup streamSetup_;

    switch (streamSetup->streamType)
    {
    case 0:
        streamSetup_.Stream = tt__StreamType__RTP_Unicast;
        break;
    case 1:
        streamSetup_.Stream = tt__StreamType__RTP_Multicast;
        break;
    default:
        break;
    }

    tt__Transport *transport = new tt__Transport;
    fun(transport, &streamSetup->transport, fun);

    streamSetup_.Transport = transport;
    request.StreamSetup = &streamSetup_;

    // 发送请求并接收回复
    if (soap_call___trt__GetStreamUri(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteFun(transport, deleteFun);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    if (response.MediaUri != nullptr)
    {
        j["uri"] = response.MediaUri->Uri ? string(response.MediaUri->Uri) : string("");
        j["invalidAfterConnect"] = response.MediaUri->InvalidAfterConnect ? string("true") : string("false");
        j["invalidAfterReboot"] = response.MediaUri->InvalidAfterReboot ? string("true") : string("false");
        j["timeout"] = response.MediaUri->Timeout ? string(response.MediaUri->Timeout) : string("");
    }

    responseJson = j.dump();
    deleteFun(transport, deleteFun);
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getSnapshotUri_V1(string &responseJson,
                                              const char *deviceXAddr,
                                              const char *userName,
                                              const char *password,
                                              const char *profileToken)
{
    string errPrefix = "getSnapshotUri_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__GetSnapshotUri request;          // 请求
    _trt__GetSnapshotUriResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__GetSnapshotUri(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    if (response.MediaUri != nullptr)
    {
        j["uri"] = response.MediaUri->Uri ? string(response.MediaUri->Uri) : string("");
        j["invalidAfterConnect"] = response.MediaUri->InvalidAfterConnect ? string("true") : string("false");
        j["invalidAfterReboot"] = response.MediaUri->InvalidAfterReboot ? string("true") : string("false");
        j["timeout"] = response.MediaUri->Timeout ? string(response.MediaUri->Timeout) : string("");
    }

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::startMulticastStreaming_V1(string &responseJson,
                                                       const char *deviceXAddr,
                                                       const char *userName,
                                                       const char *password,
                                                       const char *profileToken)
{
    string errPrefix = "startMulticastStreaming_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__StartMulticastStreaming request;          // 请求
    _trt__StartMulticastStreamingResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__StartMulticastStreaming(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::stopMulticastStreaming_V1(string &responseJson,
                                                      const char *deviceXAddr,
                                                      const char *userName,
                                                      const char *password,
                                                      const char *profileToken)
{
    string errPrefix = "stopMulticastStreaming_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__StopMulticastStreaming request;          // 请求
    _trt__StopMulticastStreamingResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__StopMulticastStreaming(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addVideoSourceConfiguration_V1(string &responseJson,
                                                           const char *deviceXAddr,
                                                           const char *userName,
                                                           const char *password,
                                                           const char *configurationToken,
                                                           const char *profileToken)
{
    string errPrefix = "addVideoSourceConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr || profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__AddVideoSourceConfiguration request;          // 请求
    _trt__AddVideoSourceConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__AddVideoSourceConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removeVideoSourceConfiguration_V1(string &responseJson,
                                                              const char *deviceXAddr,
                                                              const char *userName,
                                                              const char *password,
                                                              const char *profileToken)
{
    string errPrefix = "removeVideoSourceConfiguration_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__RemoveVideoSourceConfiguration request;          // 请求
    _trt__RemoveVideoSourceConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__RemoveVideoSourceConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addVideoEncoderConfiguration_V1(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password,
                                                            const char *configurationToken,
                                                            const char *profileToken)
{
    string errPrefix = "addVideoEncoderConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr || profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__AddVideoEncoderConfiguration request;          // 请求
    _trt__AddVideoEncoderConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__AddVideoEncoderConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removeVideoEncoderConfiguration_V1(string &responseJson,
                                                               const char *deviceXAddr,
                                                               const char *userName,
                                                               const char *password,
                                                               const char *profileToken)
{
    string errPrefix = "removeVideoEncoderConfiguration_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__RemoveVideoEncoderConfiguration request;          // 请求
    _trt__RemoveVideoEncoderConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__RemoveVideoEncoderConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addAudioSourceConfiguration_V1(string &responseJson,
                                                           const char *deviceXAddr,
                                                           const char *userName,
                                                           const char *password,
                                                           const char *configurationToken,
                                                           const char *profileToken)
{
    string errPrefix = "addAudioSourceConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr || profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__AddAudioSourceConfiguration request;          // 请求
    _trt__AddAudioSourceConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__AddAudioSourceConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removeAudioSourceConfiguration_V1(string &responseJson,
                                                              const char *deviceXAddr,
                                                              const char *userName,
                                                              const char *password,
                                                              const char *profileToken)
{
    string errPrefix = "removeAudioSourceConfiguration_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__RemoveAudioSourceConfiguration request;          // 请求
    _trt__RemoveAudioSourceConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__RemoveAudioSourceConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addAudioOutputConfiguration_V1(string &responseJson,
                                                           const char *deviceXAddr,
                                                           const char *userName,
                                                           const char *password,
                                                           const char *configurationToken,
                                                           const char *profileToken)
{
    string errPrefix = "addAudioOutputConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr || profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__AddAudioOutputConfiguration request;          // 请求
    _trt__AddAudioOutputConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__AddAudioOutputConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removeAudioOutputConfiguration_V1(string &responseJson,
                                                              const char *deviceXAddr,
                                                              const char *userName,
                                                              const char *password,
                                                              const char *profileToken)
{
    string errPrefix = "removeAudioOutputConfiguration_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__RemoveAudioOutputConfiguration request;          // 请求
    _trt__RemoveAudioOutputConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__RemoveAudioOutputConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addAudioEncoderConfiguration_V1(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password,
                                                            const char *configurationToken,
                                                            const char *profileToken)
{
    string errPrefix = "addAudioEncoderConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr || profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__AddAudioEncoderConfiguration request;          // 请求
    _trt__AddAudioEncoderConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__AddAudioEncoderConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removeAudioEncoderConfiguration_V1(string &responseJson,
                                                               const char *deviceXAddr,
                                                               const char *userName,
                                                               const char *password,
                                                               const char *profileToken)
{
    string errPrefix = "removeAudioEncoderConfiguration_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__RemoveAudioEncoderConfiguration request;          // 请求
    _trt__RemoveAudioEncoderConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__RemoveAudioEncoderConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addAudioDecoderConfiguration_V1(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password,
                                                            const char *configurationToken,
                                                            const char *profileToken)
{
    string errPrefix = "addAudioDecoderConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr || profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__AddAudioDecoderConfiguration request;          // 请求
    _trt__AddAudioDecoderConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__AddAudioDecoderConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removeAudioDecoderConfiguration_V1(string &responseJson,
                                                               const char *deviceXAddr,
                                                               const char *userName,
                                                               const char *password,
                                                               const char *profileToken)
{
    string errPrefix = "removeAudioDecoderConfiguration_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__RemoveAudioDecoderConfiguration request;          // 请求
    _trt__RemoveAudioDecoderConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__RemoveAudioDecoderConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addMetadataConfiguration_V1(string &responseJson,
                                                        const char *deviceXAddr,
                                                        const char *userName,
                                                        const char *password,
                                                        const char *configurationToken,
                                                        const char *profileToken)
{
    string errPrefix = "addMetadataConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr || profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__AddMetadataConfiguration request;          // 请求
    _trt__AddMetadataConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__AddMetadataConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removeMetadataConfiguration_V1(string &responseJson,
                                                           const char *deviceXAddr,
                                                           const char *userName,
                                                           const char *password,
                                                           const char *profileToken)
{
    string errPrefix = "removeMetadataConfiguration_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__RemoveMetadataConfiguration request;          // 请求
    _trt__RemoveMetadataConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__RemoveMetadataConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addVideoAnalyticsConfiguration_V1(string &responseJson,
                                                              const char *deviceXAddr,
                                                              const char *userName,
                                                              const char *password,
                                                              const char *configurationToken,
                                                              const char *profileToken)
{
    string errPrefix = "addVideoAnalyticsConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr || profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__AddVideoAnalyticsConfiguration request;          // 请求
    _trt__AddVideoAnalyticsConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__AddVideoAnalyticsConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removeVideoAnalyticsConfiguration_V1(string &responseJson,
                                                                 const char *deviceXAddr,
                                                                 const char *userName,
                                                                 const char *password,
                                                                 const char *profileToken)
{
    string errPrefix = "removeVideoAnalyticsConfiguration_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__RemoveVideoAnalyticsConfiguration request;          // 请求
    _trt__RemoveVideoAnalyticsConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__RemoveVideoAnalyticsConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addPTZConfiguration_V1(string &responseJson,
                                                   const char *deviceXAddr,
                                                   const char *userName,
                                                   const char *password,
                                                   const char *configurationToken,
                                                   const char *profileToken)
{
    string errPrefix = "addPTZConfiguration_V1 error";

    // 判断参数是否有效
    if (configurationToken == nullptr || profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__AddPTZConfiguration request;          // 请求
    _trt__AddPTZConfigurationResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__AddPTZConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removePTZConfiguration_V1(string &responseJson,
                                                      const char *deviceXAddr,
                                                      const char *userName,
                                                      const char *password,
                                                      const char *profileToken)
{
    string errPrefix = "removePTZConfiguration_V1 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trt__RemovePTZConfiguration request;          // 请求
    _trt__RemovePTZConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___trt__RemovePTZConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSourceConfigurations_V2(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password,
                                                            const char *configurationToken,
                                                            const char *profileToken)
{
    string errPrefix = "getVideoSourceConfigurations_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                       // 请求
    _ns1__GetVideoSourceConfigurationsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetVideoSourceConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseVideoSourceConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSourceConfigurationOptions_V2(string &responseJson,
                                                                  const char *deviceXAddr,
                                                                  const char *userName,
                                                                  const char *password,
                                                                  const char *configurationToken,
                                                                  const char *profileToken)
{
    string errPrefix = "getVideoSourceConfigurationOptions_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                             // 请求
    _ns1__GetVideoSourceConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetVideoSourceConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;

    if (auto err = jsonOperation::parseVideoSourceConfigurationOptions(jsonStr, response.Options); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSourceModes_V2(string &responseJson,
                                                   const char *deviceXAddr,
                                                   const char *userName,
                                                   const char *password,
                                                   const char *videoSourceToken)
{
    string errPrefix = "getVideoSourceModes_V2 error";

    // 判断参数是否有效
    if (videoSourceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__GetVideoSourceModes request;          // 请求
    _ns1__GetVideoSourceModesResponse response; // 回复

    // 设置请求参数
    request.VideoSourceToken = (char *)videoSourceToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetVideoSourceModes(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> modes;
    for (int i = 0; i < response.__sizeVideoSourceModes; i++)
    {
        string jsonStr;

        if (auto err = jsonOperation::parseVideoSourceMode_V2(jsonStr, response.VideoSourceModes[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(jsonStr);
        modes.push_back(item);
    }
    j["count"] = response.__sizeVideoSourceModes;
    j["modes"] = modes;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoEncoderInstances_V2(string &responseJson,
                                                        const char *deviceXAddr,
                                                        const char *userName,
                                                        const char *password,
                                                        const char *videoSourceConfigurationToken)
{
    string errPrefix = "getVideoEncoderInstances_V2 error";

    // 判断参数是否有效
    if (videoSourceConfigurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__GetVideoEncoderInstances request;          // 请求
    _ns1__GetVideoEncoderInstancesResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)videoSourceConfigurationToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetVideoEncoderInstances(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    if (response.Info != nullptr)
    {
        vector<json> codec;
        for (int i = 0; i < response.Info->__sizeCodec; i++)
        {
            json item;
            item["encoding"] = response.Info->Codec[i]->Encoding ? string(response.Info->Codec[i]->Encoding) : string("");
            item["number"] = to_string(response.Info->Codec[i]->Number);
            codec.push_back(item);
        }
        j["codec"] = codec;
        j["total"] = to_string(response.Info->Total);
    }
    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoEncoderConfigurations_V2(string &responseJson,
                                                             const char *deviceXAddr,
                                                             const char *userName,
                                                             const char *password,
                                                             const char *configurationToken,
                                                             const char *profileToken)
{
    string errPrefix = "getVideoEncoderConfigurations_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                        // 请求
    _ns1__GetVideoEncoderConfigurationsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetVideoEncoderConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseVideoEncoderConfiguration_V2(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoEncoderConfigurationOptions_V2(string &responseJson,
                                                                   const char *deviceXAddr,
                                                                   const char *userName,
                                                                   const char *password,
                                                                   const char *configurationToken,
                                                                   const char *profileToken)
{
    string errPrefix = "getVideoEncoderConfigurationOptions_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                              // 请求
    _ns1__GetVideoEncoderConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetVideoEncoderConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> options;
    for (int i = 0; i < response.__sizeOptions; i++)
    {
        string jsonStr;

        if (auto err = jsonOperation::parseVideoEncoderConfigurationOptions_V2(jsonStr, response.Options[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        options.push_back(item);
    }
    j["count"] = response.__sizeOptions;
    j["options"] = options;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioSourceConfigurations_V2(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password,
                                                            const char *configurationToken,
                                                            const char *profileToken)
{
    string errPrefix = "getAudioSourceConfigurations_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                       // 请求
    _ns1__GetAudioSourceConfigurationsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetAudioSourceConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseAudioSourceConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioSourceConfigurationOptions_V2(string &responseJson,
                                                                  const char *deviceXAddr,
                                                                  const char *userName,
                                                                  const char *password,
                                                                  const char *configurationToken,
                                                                  const char *profileToken)
{
    string errPrefix = "getAudioSourceConfigurationOptions_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                             // 请求
    _ns1__GetAudioSourceConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetAudioSourceConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<string> inputTokensAvailable;
    for (int i = 0; i < response.Options->__sizeInputTokensAvailable; i++)
    {
        inputTokensAvailable.push_back(string(response.Options->InputTokensAvailable[i]));
    }
    j["count"] = response.Options->__sizeInputTokensAvailable;
    j["inputTokensAvailable"] = inputTokensAvailable;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioOutputConfigurations_V2(string &responseJson,
                                                            const char *deviceXAddr,
                                                            const char *userName,
                                                            const char *password,
                                                            const char *configurationToken,
                                                            const char *profileToken)
{
    string errPrefix = "getAudioOutputConfigurations_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                       // 请求
    _ns1__GetAudioOutputConfigurationsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetAudioOutputConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseAudioOutputConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioOutputConfigurationOptions_V2(string &responseJson,
                                                                  const char *deviceXAddr,
                                                                  const char *userName,
                                                                  const char *password,
                                                                  const char *configurationToken,
                                                                  const char *profileToken)
{
    string errPrefix = "getAudioOutputConfigurationOptions_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                             // 请求
    _ns1__GetAudioOutputConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetAudioOutputConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioOutputConfigurationOptions(jsonStr, response.Options); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioEncoderConfigurations_V2(string &responseJson,
                                                             const char *deviceXAddr,
                                                             const char *userName,
                                                             const char *password,
                                                             const char *configurationToken,
                                                             const char *profileToken)
{
    string errPrefix = "getAudioEncoderConfigurations_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                        // 请求
    _ns1__GetAudioEncoderConfigurationsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetAudioEncoderConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseAudioEncoderConfiguration_V2(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioEncoderConfigurationOptions_V2(string &responseJson,
                                                                   const char *deviceXAddr,
                                                                   const char *userName,
                                                                   const char *password,
                                                                   const char *configurationToken,
                                                                   const char *profileToken)
{
    string errPrefix = "getAudioEncoderConfigurationOptions_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                              // 请求
    _ns1__GetAudioEncoderConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetAudioEncoderConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> options;
    for (int i = 0; i < response.__sizeOptions; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseAudioEncoderDecoderConfigurationOptions_V2(jsonStr, response.Options[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        options.push_back(item);
    }
    j["count"] = response.__sizeOptions;
    j["options"] = options;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioDecoderConfigurations_V2(string &responseJson,
                                                             const char *deviceXAddr,
                                                             const char *userName,
                                                             const char *password,
                                                             const char *configurationToken,
                                                             const char *profileToken)
{
    string errPrefix = "getAudioDecoderConfigurations_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                        // 请求
    _ns1__GetAudioDecoderConfigurationsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetAudioDecoderConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseAudioDecoderConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioDecoderConfigurationOptions_V2(string &responseJson,
                                                                   const char *deviceXAddr,
                                                                   const char *userName,
                                                                   const char *password,
                                                                   const char *configurationToken,
                                                                   const char *profileToken)
{
    string errPrefix = "getAudioDecoderConfigurationOptions_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                              // 请求
    _ns1__GetAudioDecoderConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetAudioDecoderConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> options;
    for (int i = 0; i < response.__sizeOptions; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseAudioEncoderDecoderConfigurationOptions_V2(jsonStr, response.Options[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        options.push_back(item);
    }
    j["count"] = response.__sizeOptions;
    j["options"] = options;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getMetadataConfigurations_V2(string &responseJson,
                                                         const char *deviceXAddr,
                                                         const char *userName,
                                                         const char *password,
                                                         const char *configurationToken,
                                                         const char *profileToken)
{
    string errPrefix = "getMetadataConfigurations_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                    // 请求
    _ns1__GetMetadataConfigurationsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetMetadataConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseMetadataConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getMetadataConfigurationOptions_V2(string &responseJson,
                                                               const char *deviceXAddr,
                                                               const char *userName,
                                                               const char *password,
                                                               const char *configurationToken,
                                                               const char *profileToken)
{
    string errPrefix = "getMetadataConfigurationOptions_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                          // 请求
    _ns1__GetMetadataConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetMetadataConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseMetadataConfigurationOptions(jsonStr, response.Options); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAnalyticsConfigurations_V2(string &responseJson,
                                                          const char *deviceXAddr,
                                                          const char *userName,
                                                          const char *password,
                                                          const char *configurationToken,
                                                          const char *profileToken)
{
    string errPrefix = "getAnalyticsConfigurations_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__GetConfiguration request;                     // 请求
    _ns1__GetAnalyticsConfigurationsResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetAnalyticsConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizeConfigurations; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseVideoAnalyticsConfiguration(jsonStr, response.Configurations[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizeConfigurations;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getProfiles_V2(string &responseJson,
                                           const char *deviceXAddr,
                                           const char *userName,
                                           const char *password,
                                           const char *profileToken,
                                           ONVIF_CONFIGURATION_ENUMERATION *type)

{
    string errPrefix = "getProfiles_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__GetProfiles request;          // 请求
    _ns1__GetProfilesResponse response; // 回复

    // 设置请求参数
    char *typeStr[9];
    request.Token = (char *)profileToken;
    request.Type = nullptr;
    request.__sizeType = 0;

    if (type != nullptr)
    {
        for (int i = 0; i < (int)type->size; i++)
        {
            if (i == 9)
            {
                break;
            }
            switch (type->typeArray[i])
            {
            case 0:
                typeStr[i] = (char *)"VideoSource";
                break;
            case 1:
                typeStr[i] = (char *)"AudioSource";
                break;
            case 2:
                typeStr[i] = (char *)"AudioEncoder";
                break;
            case 3:
                typeStr[i] = (char *)"Analytics";
                break;
            case 4:
                typeStr[i] = (char *)"PTZ";
                break;
            case 5:
                typeStr[i] = (char *)"Metadata";
                break;
            case 6:
                typeStr[i] = (char *)"AudioOutput";
                break;
            case 7:
                typeStr[i] = (char *)"AudioDecoder";
                break;
            case 8:
                typeStr[i] = (char *)"VideoEncoder";
                break;
            default:
                break;
            }
        }
        if (type->size > 9)
        {
            request.__sizeType = 9;
        }
        else
        {
            request.__sizeType = type->size;
        }
        request.Type = (char **)typeStr;
    }

    // 发送请求并接收回复
    if (soap_call___ns1__GetProfiles(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> profiles;
    for (int i = 0; i < response.__sizeProfiles; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseProfiles_V2(jsonStr, response.Profiles[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        profiles.push_back(item);
    }
    j["count"] = response.__sizeProfiles;
    j["profiles"] = profiles;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::createProfile_V2(string &responseJson,
                                             const char *deviceXAddr,
                                             const char *userName,
                                             const char *password,
                                             const char *name)

{
    string errPrefix = "createProfile_V2 error";

    // 判断参数是否有效
    if (name == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__CreateProfile request;          // 请求
    _ns1__CreateProfileResponse response; // 回复

    // 设置请求参数
    request.Name = (char *)name;
    request.Configuration = nullptr;
    request.__sizeConfiguration = 0;

    // 发送请求并接收回复
    if (soap_call___ns1__CreateProfile(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    j["token"] = response.Token ? string(response.Token) : string("");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::deleteProfile_V2(string &responseJson,
                                             const char *deviceXAddr,
                                             const char *userName,
                                             const char *password,
                                             const char *profileToken)

{
    string errPrefix = "deleteProfile_V2 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__DeleteProfile request;          // 请求
    _ns1__DeleteProfileResponse response; // 回复

    // 设置请求参数
    request.Token = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__DeleteProfile(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getOSDs_V2(string &responseJson,
                                       const char *deviceXAddr,
                                       const char *userName,
                                       const char *password,
                                       const char *videoSourceConfigurationToken,
                                       const char *OSDToken)
{
    string errPrefix = "getMasks_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__GetOSDs request;          // 请求
    _ns1__GetOSDsResponse response; // 回复

    // 设置请求参数
    request.OSDToken = (char *)OSDToken;
    request.ConfigurationToken = (char *)videoSourceConfigurationToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetOSDs(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<json> OSDs;
    for (int i = 0; i < response.__sizeOSDs; i++)
    {

        string jsonStr;
        if (auto err = jsonOperation::parseOSD(jsonStr, response.OSDs[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(jsonStr);
        OSDs.push_back(item);
    }
    j["count"] = response.__sizeOSDs;
    j["OSDs"] = OSDs;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getOSDOptions_V2(string &responseJson,
                                             const char *deviceXAddr,
                                             const char *userName,
                                             const char *password,
                                             const char *videoSourceConfigurationToken)
{
    string errPrefix = "getOSDOptions_V2 error";

    // 判断参数是否有效
    if (videoSourceConfigurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__GetOSDOptions request;          // 请求
    _ns1__GetOSDOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)videoSourceConfigurationToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetOSDOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseOSDOptions(jsonStr, response.OSDOptions); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::createOSD_V2(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password,
                                         ONVIF_SET_OSD_PARAM *param)
{
    string errPrefix = "createOSD_V2 error";

    // 判断参数是否有效
    if (param == nullptr || param->OSDConfigurationToken == nullptr || param->videoSourceConfigurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__CreateOSD request;          // 请求
    _ns1__CreateOSDResponse response; // 回复

    // 设置请求参数
    tt__OSDConfiguration OSD;
    if (auto err = jsonOperation::buildOSDConfiguration(OSD, param); err)
    {
        jsonOperation::deleteOSDConfiguration(&OSD);
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }
    request.OSD = &OSD;

    // 发送请求并接收回复
    if (soap_call___ns1__CreateOSD(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        jsonOperation::deleteOSDConfiguration(&OSD);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析返回内容
    json j;
    j["OSDToken"] = response.OSDToken ? string(response.OSDToken) : string("");

    responseJson = j.dump();
    jsonOperation::deleteOSDConfiguration(&OSD);
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::deleteOSD_V2(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password,
                                         const char *configurationToken)
{
    string errPrefix = "deleteOSD_V2 error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__DeleteOSD request;                // 请求
    ns1__SetConfigurationResponse response; // 回复

    // 设置请求参数
    request.OSDToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___ns1__DeleteOSD(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setOSD_V2(string &responseJson,
                                      const char *deviceXAddr,
                                      const char *userName,
                                      const char *password,
                                      ONVIF_SET_OSD_PARAM *param)
{
    string errPrefix = "setOSD_V2 error";

    // 判断参数是否有效
    if (param == nullptr || param->OSDConfigurationToken == nullptr || param->videoSourceConfigurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__SetOSD request;                   // 请求
    ns1__SetConfigurationResponse response; // 回复

    // 设置请求参数
    tt__OSDConfiguration OSD;
    if (auto err = jsonOperation::buildOSDConfiguration(OSD, param); err)
    {
        jsonOperation::deleteOSDConfiguration(&OSD);
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }
    request.OSD = &OSD;

    // 发送请求并接收回复
    if (soap_call___ns1__SetOSD(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        jsonOperation::deleteOSDConfiguration(&OSD);
        deleteSoap(soapPtr);
        return err;
    }

    jsonOperation::deleteOSDConfiguration(&OSD);
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getMasks_V2(string &responseJson,
                                        const char *deviceXAddr,
                                        const char *userName,
                                        const char *password,
                                        const char *videoSourceConfigurationToken,
                                        const char *maskToken)
{
    string errPrefix = "getMasks_V2 error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__GetMasks request;          // 请求
    _ns1__GetMasksResponse response; // 回复

    // 设置请求参数
    request.Token = (char *)maskToken;
    request.ConfigurationToken = (char *)videoSourceConfigurationToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetMasks(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> masks;
    for (int i = 0; i < response.__sizeMasks; i++)
    {
        json item;
        item["token"] = response.Masks[i]->token ? string(response.Masks[i]->token) : string("");
        item["configurationToken"] = response.Masks[i]->ConfigurationToken ? string(response.Masks[i]->ConfigurationToken) : string("");

        if (response.Masks[i]->Polygon != nullptr)
        {
            auto polygon = response.Masks[i]->Polygon;
            vector<json> point;
            for (int i = 0; i < polygon->__sizePoint; i++)
            {
                json pointJson;
                pointJson["x"] = polygon->Point[i]->x ? to_string(*polygon->Point[i]->x) : string("");
                pointJson["y"] = polygon->Point[i]->y ? to_string(*polygon->Point[i]->y) : string("");
                point.push_back(pointJson);
            }
            item["polygon"]["point"] = point;
        }

        item["type"] = response.Masks[i]->Type ? string(response.Masks[i]->Type) : string("");
        if (response.Masks[i]->Color != nullptr)
        {
            item["color"]["x"] = to_string(response.Masks[i]->Color->X);
            item["color"]["y"] = to_string(response.Masks[i]->Color->Y);
            item["color"]["z"] = to_string(response.Masks[i]->Color->Z);
            item["color"]["likelihood"] = response.Masks[i]->Color->Likelihood
                                              ? to_string(*response.Masks[i]->Color->Likelihood)
                                              : string("");
            item["color"]["colorspace"] = response.Masks[i]->Color->Colorspace ? string(response.Masks[i]->Color->Colorspace) : string("");
        }
        item["enabled"] = response.Masks[i]->Enabled ? string("true") : string("false");

        masks.push_back(item);
    }
    j["count"] = response.__sizeMasks;
    j["masks"] = masks;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getMaskOptions_V2(string &responseJson,
                                              const char *deviceXAddr,
                                              const char *userName,
                                              const char *password,
                                              const char *videoSourceConfigurationToken)
{
    string errPrefix = "getMaskOptions_V2 error";

    // 判断参数是否有效
    if (videoSourceConfigurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__GetMaskOptions request;          // 请求
    _ns1__GetMaskOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)videoSourceConfigurationToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetMaskOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    if (response.Options->RectangleOnly != nullptr)
    {
        j["rectangleOnly"] = *response.Options->RectangleOnly ? string("true") : string("false");
    }
    if (response.Options->SingleColorOnly != nullptr)
    {
        j["singleColorOnly"] = *response.Options->SingleColorOnly ? string("true") : string("false");
    }
    j["maxMasks"] = to_string(response.Options->MaxMasks);
    j["maxPoints"] = to_string(response.Options->MaxPoints);

    vector<string> types;
    for (int i = 0; i < response.Options->__sizeTypes; i++)
    {
        types.push_back(string(response.Options->Types[i]));
    }
    j["type"] = types;

    if (response.Options->Color != nullptr)
    {
        auto color = response.Options->Color;

        vector<json> colorList;
        for (int i = 0; i < color->__sizeColorList; i++)
        {
            json item;
            item["x"] = to_string(color->ColorList[i]->X);
            item["y"] = to_string(color->ColorList[i]->Y);
            item["z"] = to_string(color->ColorList[i]->Z);
            item["colorspace"] = color->ColorList[i]->Colorspace ? string(color->ColorList[i]->Colorspace) : string("");
            item["likelihood"] = color->ColorList[i]->Likelihood ? to_string(*color->ColorList[i]->Likelihood) : string("");
            colorList.push_back(item);
        }
        j["color"]["colorList"] = colorList;

        vector<json> colorspaceRange;
        for (int i = 0; i < color->__sizeColorspaceRange; i++)
        {
            json item;
            item["x"] = to_string(color->ColorspaceRange[i]->X->Min) +
                        string(" ~ ") +
                        to_string(color->ColorspaceRange[i]->X->Max);
            item["y"] = to_string(color->ColorspaceRange[i]->Y->Min) +
                        string(" ~ ") +
                        to_string(color->ColorspaceRange[i]->Y->Max);
            item["z"] = to_string(color->ColorspaceRange[i]->Z->Min) +
                        string(" ~ ") +
                        to_string(color->ColorspaceRange[i]->Z->Max);
            item["colorspace"] = color->ColorspaceRange[i]->Colorspace ? string(color->ColorspaceRange[i]->Colorspace) : string("");
            colorspaceRange.push_back(item);
        }
        j["color"]["colorspaceRange"] = colorspaceRange;
    }

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getStreamUri_V2(string &responseJson,
                                            const char *deviceXAddr,
                                            const char *userName,
                                            const char *password,
                                            const char *profileToken,
                                            ONVIF_TRANSPORT_PROTOCOL_V2 protocol)
{
    string errPrefix = "getStreamUri_V2 error";

    // 判断参数是否有效
    if (profileToken == nullptr || protocol.protocolsName > 5)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__GetStreamUri request;          // 请求
    _ns1__GetStreamUriResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    switch (protocol.protocolsName)
    {
    case 0:
        request.Protocol = (char *)"RtspUnicast";
        break;
    case 1:
        request.Protocol = (char *)"RtspMulticast";
        break;
    case 2:
        request.Protocol = (char *)"RTSP";
        break;
    case 3:
        request.Protocol = (char *)"RtspsUnicast";
        break;
    case 4:
        request.Protocol = (char *)"RtspsMulticast";
        break;
    case 5:
        request.Protocol = (char *)"RtspOverHttp";
        break;

    default:
        break;
    }

    // 发送请求并接收回复
    if (soap_call___ns1__GetStreamUri(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    j["uri"] = response.Uri ? string(response.Uri) : string("");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getSnapshotUri_V2(string &responseJson,
                                              const char *deviceXAddr,
                                              const char *userName,
                                              const char *password,
                                              const char *profileToken)
{
    string errPrefix = "getSnapshotUri_V2 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__GetSnapshotUri request;          // 请求
    _ns1__GetSnapshotUriResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__GetSnapshotUri(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    j["uri"] = response.Uri ? string(response.Uri) : string("");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::startMulticastStreaming_V2(string &responseJson,
                                                       const char *deviceXAddr,
                                                       const char *userName,
                                                       const char *password,
                                                       const char *profileToken)
{
    string errPrefix = "startMulticastStreaming_V2 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__StartStopMulticastStreaming request; // 请求
    ns1__SetConfigurationResponse response;   // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__StartMulticastStreaming(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::stopMulticastStreaming_V2(string &responseJson,
                                                      const char *deviceXAddr,
                                                      const char *userName,
                                                      const char *password,
                                                      const char *profileToken)
{
    string errPrefix = "stopMulticastStreaming_V2 error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    ns1__StartStopMulticastStreaming request; // 请求
    ns1__SetConfigurationResponse response;   // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___ns1__StopMulticastStreaming(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addConfiguration_V2(string &responseJson,
                                                const char *deviceXAddr,
                                                const char *userName,
                                                const char *password,
                                                const char *profileToken,
                                                ONVIF_CONFIGURATION_ENUMERATION *configurations)

{
    string errPrefix = "addConfiguration_V2 error";

    // 判断参数是否有效
    if (profileToken == nullptr || configurations == nullptr || configurations->size == 0 ||
        configurations->tokenArray == nullptr || configurations->tokenArray == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__AddConfiguration request;          // 请求
    _ns1__AddConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;
    request.Name = nullptr;

    ns1__ConfigurationRef **configurationRef = nullptr;

    configurationRef = new ns1__ConfigurationRef *[configurations->size];
    for (int i = 0; i < (int)configurations->size; i++)
    {
        configurationRef[i] = new ns1__ConfigurationRef;
        switch (configurations->typeArray[i])
        {
        case 0:
            configurationRef[i]->Type = (char *)"VideoSource";
            break;
        case 1:
            configurationRef[i]->Type = (char *)"AudioSource";
            break;
        case 2:
            configurationRef[i]->Type = (char *)"AudioEncoder";
            break;
        case 3:
            configurationRef[i]->Type = (char *)"Analytics";
            break;
        case 4:
            configurationRef[i]->Type = (char *)"PTZ";
            break;
        case 5:
            configurationRef[i]->Type = (char *)"Metadata";
            break;
        case 6:
            configurationRef[i]->Type = (char *)"AudioOutput";
            break;
        case 7:
            configurationRef[i]->Type = (char *)"AudioDecoder";
            break;
        case 8:
            configurationRef[i]->Type = (char *)"VideoEncoder";
            break;
        default:
            break;
        }
        configurationRef[i]->Token = (char *)configurations->tokenArray[i];
    }

    request.Configuration = configurationRef;
    request.__sizeConfiguration = configurations->size;

    // 发送请求并接收回复
    if (soap_call___ns1__AddConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        for (int i = 0; i < (int)configurations->size; i++)
        {
            delete configurationRef[i];
        }
        delete[] configurationRef;
        deleteSoap(soapPtr);
        return err;
    }

    for (int i = 0; i < (int)configurations->size; i++)
    {
        delete configurationRef[i];
    }
    delete[] configurationRef;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removeConfiguration_V2(string &responseJson,
                                                   const char *deviceXAddr,
                                                   const char *userName,
                                                   const char *password,
                                                   const char *profileToken,
                                                   ONVIF_CONFIGURATION_ENUMERATION *configurations)

{
    string errPrefix = "removeConfiguration_V2 error";

    // 判断参数是否有效
    if (profileToken == nullptr || configurations == nullptr || configurations->size == 0 ||
        configurations->tokenArray == nullptr || configurations->tokenArray == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns1__RemoveConfiguration request;          // 请求
    _ns1__RemoveConfigurationResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    ns1__ConfigurationRef **configurationRef = nullptr;

    configurationRef = new ns1__ConfigurationRef *[configurations->size];
    for (int i = 0; i < (int)configurations->size; i++)
    {
        configurationRef[i] = new ns1__ConfigurationRef;
        switch (configurations->typeArray[i])
        {
        case 0:
            configurationRef[i]->Type = (char *)"VideoSource";
            break;
        case 1:
            configurationRef[i]->Type = (char *)"AudioSource";
            break;
        case 2:
            configurationRef[i]->Type = (char *)"AudioEncoder";
            break;
        case 3:
            configurationRef[i]->Type = (char *)"Analytics";
            break;
        case 4:
            configurationRef[i]->Type = (char *)"PTZ";
            break;
        case 5:
            configurationRef[i]->Type = (char *)"Metadata";
            break;
        case 6:
            configurationRef[i]->Type = (char *)"AudioOutput";
            break;
        case 7:
            configurationRef[i]->Type = (char *)"AudioDecoder";
            break;
        case 8:
            configurationRef[i]->Type = (char *)"VideoEncoder";
            break;
        default:
            break;
        }
        configurationRef[i]->Token = (char *)configurations->tokenArray[i];
    }

    request.Configuration = configurationRef;
    request.__sizeConfiguration = configurations->size;

    // 发送请求并接收回复
    if (soap_call___ns1__RemoveConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        for (int i = 0; i < (int)configurations->size; i++)
        {
            delete configurationRef[i];
        }
        delete[] configurationRef;
        deleteSoap(soapPtr);
        return err;
    }

    for (int i = 0; i < (int)configurations->size; i++)
    {
        delete configurationRef[i];
    }
    delete[] configurationRef;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoOutputs_DeviceIO(string &responseJson,
                                                     const char *deviceXAddr,
                                                     const char *userName,
                                                     const char *password)
{
    string errPrefix = "getVideoOutputs_DeviceIO error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tmd__GetVideoOutputs request;          // 请求
    _tmd__GetVideoOutputsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tmd__GetVideoOutputs(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> videoOutputs;
    for (int i = 0; i < response.__sizeVideoOutputs; i++)
    {
        json outputItem;

        outputItem["token"] = response.VideoOutputs[i]->token ? string(response.VideoOutputs[i]->token) : string("");

        vector<json> paneLayouts;
        for (int ii = 0; ii < response.VideoOutputs[i]->Layout->__sizePaneLayout; ii++)
        {
            json paneLayoutItem;
            paneLayoutItem["pane"] = response.VideoOutputs[i]->Layout->PaneLayout[ii]->Pane
                                         ? string(response.VideoOutputs[i]->Layout->PaneLayout[ii]->Pane)
                                         : string("");
            if (response.VideoOutputs[i]->Layout->PaneLayout[ii]->Area == nullptr)
            {
                continue;
            }
            paneLayoutItem["area"]["top"] = response.VideoOutputs[i]->Layout->PaneLayout[ii]->Area->top
                                                ? to_string(*response.VideoOutputs[i]->Layout->PaneLayout[ii]->Area->top)
                                                : string("");
            paneLayoutItem["area"]["left"] = response.VideoOutputs[i]->Layout->PaneLayout[ii]->Area->left
                                                 ? to_string(*response.VideoOutputs[i]->Layout->PaneLayout[ii]->Area->left)
                                                 : string("");
            paneLayoutItem["area"]["bottom"] = response.VideoOutputs[i]->Layout->PaneLayout[ii]->Area->bottom
                                                   ? to_string(*response.VideoOutputs[i]->Layout->PaneLayout[ii]->Area->bottom)
                                                   : string("");
            paneLayoutItem["area"]["right"] = response.VideoOutputs[i]->Layout->PaneLayout[ii]->Area->right
                                                  ? to_string(*response.VideoOutputs[i]->Layout->PaneLayout[ii]->Area->right)
                                                  : string("");

            paneLayouts.push_back(paneLayoutItem);
        }
        outputItem["paneLayouts"] = paneLayouts;

        if (response.VideoOutputs[i]->Resolution != nullptr)
        {
            outputItem["resolution"]["width"] = to_string(response.VideoOutputs[i]->Resolution->Width);
            outputItem["resolution"]["height"] = to_string(response.VideoOutputs[i]->Resolution->Height);
        }
        outputItem["refreshRate"] = response.VideoOutputs[i]->RefreshRate ? to_string(*response.VideoOutputs[i]->RefreshRate) : string("");
        outputItem["aspectRatio"] = response.VideoOutputs[i]->AspectRatio ? to_string(*response.VideoOutputs[i]->AspectRatio) : string("");

        videoOutputs.push_back(outputItem);
    }

    j["count"] = response.__sizeVideoOutputs;
    j["videoOutputs"] = videoOutputs;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSources_DeviceIO(string &responseJson,
                                                     const char *deviceXAddr,
                                                     const char *userName,
                                                     const char *password)
{
    string errPrefix = "getVideoSources_DeviceIO error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    tmd__Get request;          // 请求
    tmd__GetResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tmd__GetVideoSources(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<string> tokens;
    for (int i = 0; i < response.__sizeToken; i++)
    {
        tokens.push_back(string(response.Token[i]));
    }

    j["count"] = response.__sizeToken;
    j["token"] = tokens;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoOutputConfiguration_DeviceIO(string &responseJson,
                                                                 const char *deviceXAddr,
                                                                 const char *userName,
                                                                 const char *password,
                                                                 const char *videoOutputToken)
{
    string errPrefix = "getVideoOutputConfiguration_DeviceIO error";

    // 判断参数是否有效
    if (videoOutputToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tmd__GetVideoOutputConfiguration request;          // 请求
    _tmd__GetVideoOutputConfigurationResponse response; // 回复

    // 设置请求参数
    request.VideoOutputToken = (char *)videoOutputToken;

    // 发送请求并接收回复
    if (soap_call___tmd__GetVideoOutputConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseVideoOutputConfiguration(jsonStr, response.VideoOutputConfiguration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoOutputConfigurationOptions_DeviceIO(string &responseJson,
                                                                        const char *deviceXAddr,
                                                                        const char *userName,
                                                                        const char *password,
                                                                        const char *videoOutputToken)
{
    string errPrefix = "getVideoOutputConfigurationOptions_DeviceIO error";

    // 判断参数是否有效
    if (videoOutputToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tmd__GetVideoOutputConfigurationOptions request;          // 请求
    _tmd__GetVideoOutputConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.VideoOutputToken = (char *)videoOutputToken;

    // 发送请求并接收回复
    if (soap_call___tmd__GetVideoOutputConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // response未定义内容

    responseJson = "";
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSourceConfiguration_DeviceIO(string &responseJson,
                                                                 const char *deviceXAddr,
                                                                 const char *userName,
                                                                 const char *password,
                                                                 const char *videoSourceToken)
{
    string errPrefix = "getVideoSourceConfiguration_DeviceIO error";

    // 判断参数是否有效
    if (videoSourceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tmd__GetVideoSourceConfiguration request;          // 请求
    _tmd__GetVideoSourceConfigurationResponse response; // 回复

    // 设置请求参数
    request.VideoSourceToken = (char *)videoSourceToken;

    // 发送请求并接收回复
    if (soap_call___tmd__GetVideoSourceConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里

    string jsonStr;

    if (auto err = jsonOperation::parseVideoSourceConfiguration(jsonStr, response.VideoSourceConfiguration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getVideoSourceConfigurationOptions_DeviceIO(string &responseJson,
                                                                        const char *deviceXAddr,
                                                                        const char *userName,
                                                                        const char *password,
                                                                        const char *videoSourceToken)
{
    string errPrefix = "getVideoSourceConfigurationOptions_DeviceIO error";

    // 判断参数是否有效
    if (videoSourceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tmd__GetVideoSourceConfigurationOptions request;          // 请求
    _tmd__GetVideoSourceConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.VideoSourceToken = (char *)videoSourceToken;

    // 发送请求并接收回复
    if (soap_call___tmd__GetVideoSourceConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里

    string jsonStr;
    if (auto err = jsonOperation::parseVideoSourceConfigurationOptions(jsonStr, response.VideoSourceConfigurationOptions); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioOutputs_DeviceIO(string &responseJson,
                                                     const char *deviceXAddr,
                                                     const char *userName,
                                                     const char *password)
{
    string errPrefix = "getAudioOutputs_DeviceIO error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    tmd__Get request;          // 请求
    tmd__GetResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tmd__GetAudioOutputs(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<string> tokens;
    for (int i = 0; i < response.__sizeToken; i++)
    {
        tokens.push_back(string(response.Token[i]));
    }

    j["count"] = response.__sizeToken;
    j["token"] = tokens;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioSources_DeviceIO(string &responseJson,
                                                     const char *deviceXAddr,
                                                     const char *userName,
                                                     const char *password)
{
    string errPrefix = "getAudioSources_DeviceIO error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    tmd__Get request;          // 请求
    tmd__GetResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tmd__GetAudioSources(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    vector<string> tokens;
    for (int i = 0; i < response.__sizeToken; i++)
    {
        tokens.push_back(string(response.Token[i]));
    }

    j["count"] = response.__sizeToken;
    j["token"] = tokens;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioOutputConfiguration_DeviceIO(string &responseJson,
                                                                 const char *deviceXAddr,
                                                                 const char *userName,
                                                                 const char *password,
                                                                 const char *audioOutputToken)
{
    string errPrefix = "getAudioOutputConfiguration_DeviceIO error";

    // 判断参数是否有效
    if (audioOutputToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tmd__GetAudioOutputConfiguration request;          // 请求
    _tmd__GetAudioOutputConfigurationResponse response; // 回复

    // 设置请求参数
    request.AudioOutputToken = (char *)audioOutputToken;

    // 发送请求并接收回复
    if (soap_call___tmd__GetAudioOutputConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioOutputConfiguration(jsonStr, response.AudioOutputConfiguration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioOutputConfigurationOptions_DeviceIO(string &responseJson,
                                                                        const char *deviceXAddr,
                                                                        const char *userName,
                                                                        const char *password,
                                                                        const char *audioOutputToken)
{
    string errPrefix = "getAudioOutputConfigurationOptions_DeviceIO error";

    // 判断参数是否有效
    if (audioOutputToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tmd__GetAudioOutputConfigurationOptions request;          // 请求
    _tmd__GetAudioOutputConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.AudioOutputToken = (char *)audioOutputToken;

    // 发送请求并接收回复
    if (soap_call___tmd__GetAudioOutputConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioOutputConfigurationOptions(jsonStr, response.AudioOutputOptions); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioSourceConfiguration_DeviceIO(string &responseJson,
                                                                 const char *deviceXAddr,
                                                                 const char *userName,
                                                                 const char *password,
                                                                 const char *audioSourceToken)
{
    string errPrefix = "getAudioSourceConfiguration_DeviceIO error";

    // 判断参数是否有效
    if (audioSourceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tmd__GetAudioSourceConfiguration request;          // 请求
    _tmd__GetAudioSourceConfigurationResponse response; // 回复

    // 设置请求参数
    request.AudioSourceToken = (char *)audioSourceToken;

    // 发送请求并接收回复
    if (soap_call___tmd__GetAudioSourceConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parseAudioSourceConfiguration(jsonStr, response.AudioSourceConfiguration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getAudioSourceConfigurationOptions_DeviceIO(string &responseJson,
                                                                        const char *deviceXAddr,
                                                                        const char *userName,
                                                                        const char *password,
                                                                        const char *audioSourceToken)
{
    string errPrefix = "getAudioSourceConfigurationOptions_DeviceIO error";

    // 判断参数是否有效
    if (audioSourceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tmd__GetAudioSourceConfigurationOptions request;          // 请求
    _tmd__GetAudioSourceConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.AudioSourceToken = (char *)audioSourceToken;

    // 发送请求并接收回复
    if (soap_call___tmd__GetAudioSourceConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<string> inputTokensAvailable;
    for (int i = 0; i < response.AudioSourceOptions->__sizeInputTokensAvailable; i++)
    {
        inputTokensAvailable.push_back(string(response.AudioSourceOptions->InputTokensAvailable[i]));
    }
    j["count"] = response.AudioSourceOptions->__sizeInputTokensAvailable;
    j["inputTokensAvailable"] = inputTokensAvailable;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getNodes(string &responseJson,
                                     const char *deviceXAddr,
                                     const char *userName,
                                     const char *password)
{
    string errPrefix = "getNodes error";
    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__GetNodes request;          // 请求
    _tptz__GetNodesResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tptz__GetNodes(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    vector<json> items;
    for (int i = 0; i < response.__sizePTZNode; i++)
    {
        json nodeItem;
        nodeItem["token"] = response.PTZNode[i]->token ? string(response.PTZNode[i]->token) : string("");
        nodeItem["name"] = string(response.PTZNode[i]->Name);
        nodeItem["maximumNumberOfPresets"] = std::to_string(response.PTZNode[i]->MaximumNumberOfPresets);
        nodeItem["homeSupported"] = response.PTZNode[i]->HomeSupported ? "true" : "false";
        nodeItem["fixedHomePosition"] = response.PTZNode[i]->FixedHomePosition ? "true" : "false";
        nodeItem["geoMove"] = response.PTZNode[i]->GeoMove ? "true" : "false";

        string auxiliaryCommands = "";
        for (int j = 0; j < response.PTZNode[i]->__sizeAuxiliaryCommands; j++)
        {
            auxiliaryCommands = auxiliaryCommands + string(" ") + string(response.PTZNode[i]->AuxiliaryCommands[j]);
        }
        nodeItem["auxiliaryCommands"] = auxiliaryCommands;

        string supportedPTZSpaces = "";
        if (response.PTZNode[i]->SupportedPTZSpaces)
        {
            if (auto err = jsonOperation::parsePTZSpace(supportedPTZSpaces, response.PTZNode[i]->SupportedPTZSpaces); err)
            {
                deleteSoap(soapPtr);
                return makeErrorStr(errPrefix, *err);
            }
        }

        if (supportedPTZSpaces != "")
        {
            json supportedPTZSpacesJson = json::parse(supportedPTZSpaces);
            nodeItem["supportedPTZSpaces"] = supportedPTZSpacesJson;
        }

        if (response.PTZNode[i]->Extension != nullptr && response.PTZNode[i]->Extension->SupportedPresetTour != nullptr)
        {
            nodeItem["extension"]["SupportedPresetTour"]["maximumNumberOfPresetTours"] = to_string(response.PTZNode[i]->Extension->SupportedPresetTour->MaximumNumberOfPresetTours);

            vector<string> PTZPresetTourOperation;
            for (int i_ = 0; i_ < response.PTZNode[i]->Extension->SupportedPresetTour->__sizePTZPresetTourOperation; i_++)
            {
                switch (response.PTZNode[i]->Extension->SupportedPresetTour->PTZPresetTourOperation[i_])
                {
                case tt__PTZPresetTourOperation__Start:
                    PTZPresetTourOperation.push_back("start");
                    break;
                case tt__PTZPresetTourOperation__Stop:
                    PTZPresetTourOperation.push_back("stop");
                    break;
                case tt__PTZPresetTourOperation__Pause:
                    PTZPresetTourOperation.push_back("pause");
                    break;
                case tt__PTZPresetTourOperation__Extended:
                    PTZPresetTourOperation.push_back("extended");
                    break;
                default:
                    break;
                }
            }
            nodeItem["extension"]["SupportedPresetTour"]["PTZPresetTourOperation"] = PTZPresetTourOperation;
        }

        items.push_back(nodeItem);
    }

    json j;
    j["count"] = response.__sizePTZNode;
    j["nodes"] = items;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getNode(string &responseJson,
                                    const char *deviceXAddr,
                                    const char *userName,
                                    const char *password,
                                    const char *nodeToken)
{
    string errPrefix = "getNode error";

    // 判断参数是否有效
    if (nodeToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__GetNode request;          // 请求
    _tptz__GetNodeResponse response; // 回复

    // 设置请求参数
    request.NodeToken = (char *)nodeToken;

    // 发送请求并接收回复
    if (soap_call___tptz__GetNode(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json nodeItem;
    nodeItem["token"] = response.PTZNode->token ? string(response.PTZNode->token) : string("");
    nodeItem["name"] = string(response.PTZNode->Name);
    nodeItem["maximumNumberOfPresets"] = std::to_string(response.PTZNode->MaximumNumberOfPresets);
    nodeItem["homeSupported"] = response.PTZNode->HomeSupported ? "true" : "false";
    nodeItem["fixedHomePosition"] = response.PTZNode->FixedHomePosition ? "true" : "false";
    nodeItem["geoMove"] = response.PTZNode->GeoMove ? "true" : "false";

    string auxiliaryCommands = "";
    for (int j = 0; j < response.PTZNode->__sizeAuxiliaryCommands; j++)
    {
        auxiliaryCommands = auxiliaryCommands + string(" ") + string(response.PTZNode->AuxiliaryCommands[j]);
    }
    nodeItem["auxiliaryCommands"] = auxiliaryCommands;

    string supportedPTZSpaces = "";
    if (response.PTZNode->SupportedPTZSpaces)
    {
        if (auto err = jsonOperation::parsePTZSpace(supportedPTZSpaces, response.PTZNode->SupportedPTZSpaces); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    if (supportedPTZSpaces != "")
    {
        json supportedPTZSpacesJson = json::parse(supportedPTZSpaces);
        nodeItem["supportedPTZSpaces"] = supportedPTZSpacesJson;
    }

    if (response.PTZNode->Extension != nullptr && response.PTZNode->Extension->SupportedPresetTour != nullptr)
    {
        nodeItem["extension"]["SupportedPresetTour"]["maximumNumberOfPresetTours"] = to_string(response.PTZNode->Extension->SupportedPresetTour->MaximumNumberOfPresetTours);

        vector<string> PTZPresetTourOperation;
        for (int i_ = 0; i_ < response.PTZNode->Extension->SupportedPresetTour->__sizePTZPresetTourOperation; i_++)
        {
            switch (response.PTZNode->Extension->SupportedPresetTour->PTZPresetTourOperation[i_])
            {
            case tt__PTZPresetTourOperation__Start:
                PTZPresetTourOperation.push_back("start");
                break;
            case tt__PTZPresetTourOperation__Stop:
                PTZPresetTourOperation.push_back("stop");
                break;
            case tt__PTZPresetTourOperation__Pause:
                PTZPresetTourOperation.push_back("pause");
                break;
            case tt__PTZPresetTourOperation__Extended:
                PTZPresetTourOperation.push_back("extended");
                break;
            default:
                break;
            }
        }
        nodeItem["extension"]["SupportedPresetTour"]["PTZPresetTourOperation"] = PTZPresetTourOperation;
    }

    responseJson = nodeItem.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getPTZConfigurations(string &responseJson,
                                                 const char *deviceXAddr,
                                                 const char *userName,
                                                 const char *password)
{
    string errPrefix = "getPTZConfigurations error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__GetConfigurations request;          // 请求
    _tptz__GetConfigurationsResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tptz__GetConfigurations(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> configurations;
    for (int i = 0; i < response.__sizePTZConfiguration; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parsePTZConfiguration(jsonStr, response.PTZConfiguration[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr);
        configurations.push_back(item);
    }
    j["count"] = response.__sizePTZConfiguration;
    j["configurations"] = configurations;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getPTZConfiguration(string &responseJson,
                                                const char *deviceXAddr,
                                                const char *userName,
                                                const char *password,
                                                const char *configurationToken)
{
    string errPrefix = "getPTZConfiguration error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__GetConfiguration request;          // 请求
    _tptz__GetConfigurationResponse response; // 回复

    // 设置请求参数
    request.PTZConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___tptz__GetConfiguration(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parsePTZConfiguration(jsonStr, response.PTZConfiguration); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getPTZConfigurationOptions(string &responseJson,
                                                       const char *deviceXAddr,
                                                       const char *userName,
                                                       const char *password,
                                                       const char *configurationToken)
{
    string errPrefix = "getConfigurationOptions error";

    // 判断参数是否有效
    if (configurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__GetConfigurationOptions request;          // 请求
    _tptz__GetConfigurationOptionsResponse response; // 回复

    // 设置请求参数
    request.ConfigurationToken = (char *)configurationToken;

    // 发送请求并接收回复
    if (soap_call___tptz__GetConfigurationOptions(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;
    if (auto err = jsonOperation::parsePTZConfigurationOptions(jsonStr, response.PTZConfigurationOptions); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getPTZStatus(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password,
                                         const char *profileToken)
{
    string errPrefix = "getPTZStatus error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__GetStatus request;          // 请求
    _tptz__GetStatusResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___tptz__GetStatus(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    if (response.PTZStatus != nullptr)
    {
        j["utcTime"] = utils.time_tToDateTime(response.PTZStatus->UtcTime);

        string position = "";
        jsonOperation::parsePTZVector(position, response.PTZStatus->Position);
        if (position != "")
        {
            j["position"] = json::parse(position);
        }

        j["error"] = response.PTZStatus->Error ? string(response.PTZStatus->Error) : string("");

        if (response.PTZStatus->MoveStatus != nullptr)
        {
            if (response.PTZStatus->MoveStatus->PanTilt != nullptr)
            {
                switch (*response.PTZStatus->MoveStatus->PanTilt)
                {
                case tt__MoveStatus__IDLE:
                    j["moveStatus"]["panTilt"] = string("idle");
                    break;
                case tt__MoveStatus__MOVING:
                    j["moveStatus"]["panTilt"] = string("moving");
                    break;
                case tt__MoveStatus__UNKNOWN:
                    j["moveStatus"]["panTilt"] = string("unknown");
                    break;
                default:
                    break;
                }
            }

            if (response.PTZStatus->MoveStatus->Zoom != nullptr)
            {
                switch (*response.PTZStatus->MoveStatus->Zoom)
                {
                case tt__MoveStatus__IDLE:
                    j["moveStatus"]["zoom"] = string("idle");
                    break;
                case tt__MoveStatus__MOVING:
                    j["moveStatus"]["zoom"] = string("moving");
                    break;
                case tt__MoveStatus__UNKNOWN:
                    j["moveStatus"]["zoom"] = string("unknown");
                    break;
                default:
                    break;
                }
            }
        }
    }

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::absoluteMove(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password,
                                         const char *profileToken,
                                         ONVIF_PTZ_MOVE_PARAM *move)
{
    string errPrefix = "absoluteMove error";

    // 判断参数是否有效
    if (profileToken == nullptr || move == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__AbsoluteMove request;          // 请求
    _tptz__AbsoluteMoveResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    tt__PTZVector position;
    tt__Vector2D posPanTilt;
    tt__Vector1D posZoom;
    if (move->panTiltEnable == false)
    {
        position.PanTilt = nullptr;
    }
    else
    {
        posPanTilt.x = move->panPos;
        posPanTilt.y = move->tiltPos;
        switch (move->panTiltSpace)
        {
        case 0:
            posPanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace";
            break;
        case 1:
            posPanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/SphericalPositionSpace";
            break;
        case 2:
            posPanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace";
            break;

        default:
            break;
        }
        position.PanTilt = &posPanTilt;
    }
    if (move->zoomEnable == false)
    {
        position.Zoom = nullptr;
    }
    else
    {
        posZoom.x = move->zoomVal;
        switch (move->zoomSpace)
        {
        case 0:
            posZoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/PositionGenericSpace";
            break;
        case 1:
            posZoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/PositionSpaceMillimeter";
            break;

        case 2:
            posZoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/TranslationGenericSpace";
            break;

        default:
            break;
        }
        position.Zoom = &posZoom;
    }

    request.Position = &position;

    tt__PTZSpeed Speed;
    Speed.Zoom = nullptr;
    Speed.PanTilt = nullptr;
    tt__Vector2D PanTilt;
    tt__Vector1D Zoom;
    if (move->moveSpeed == nullptr)
    {
        request.Speed = nullptr;
    }
    else
    {
        auto speed = move->moveSpeed;
        if (speed->zoomSpeedEnable)
        {
            switch (speed->zoomSpace)
            {
            case 0:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace";
                break;
            case 1:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/SpeedSpaceMillimeter";
                break;
            case 2:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace";
                break;
            default:
                break;
            }
            Zoom.x = speed->zoomSpeed;
            Speed.Zoom = &Zoom;
        }

        if (speed->panTiltSpeedEnable)
        {
            switch (speed->panTiltSpace)
            {
            case 0:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace";
                break;
            case 1:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/SpeedSpaceDegrees";
                break;
            case 2:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace";
                break;
            case 3:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocitySpaceDegrees";
                break;

            default:
                break;
            }
            PanTilt.x = speed->panSpeed;
            PanTilt.y = speed->tiltSpeed;
            Speed.PanTilt = &PanTilt;
        }
        request.Speed = &Speed;
    }

    // 发送请求并接收回复
    if (soap_call___tptz__AbsoluteMove(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::relativeMove(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password,
                                         const char *profileToken,
                                         ONVIF_PTZ_MOVE_PARAM *move)
{
    string errPrefix = "relativeMove error";

    // 判断参数是否有效
    if (profileToken == nullptr || move == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__RelativeMove request;          // 请求
    _tptz__RelativeMoveResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    tt__PTZVector position;
    tt__Vector2D posPanTilt;
    tt__Vector1D posZoom;
    if (move->panTiltEnable == false)
    {
        position.PanTilt = nullptr;
    }
    else
    {
        posPanTilt.x = move->panPos;
        posPanTilt.y = move->tiltPos;
        switch (move->panTiltSpace)
        {
        case 0:
            posPanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace";
            break;
        case 1:
            posPanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/SphericalPositionSpace";
            break;
        case 2:
            posPanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace";
            break;

        default:
            break;
        }
        position.PanTilt = &posPanTilt;
    }
    if (move->zoomEnable == false)
    {
        position.Zoom = nullptr;
    }
    else
    {
        posZoom.x = move->zoomVal;
        switch (move->zoomSpace)
        {
        case 0:
            posZoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/PositionGenericSpace";
            break;
        case 1:
            posZoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/PositionSpaceMillimeter";
            break;

        case 2:
            posZoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/TranslationGenericSpace";
            break;

        default:
            break;
        }
        position.Zoom = &posZoom;
    }

    request.Translation = &position;

    tt__PTZSpeed Speed;
    Speed.Zoom = nullptr;
    Speed.PanTilt = nullptr;
    tt__Vector2D PanTilt;
    tt__Vector1D Zoom;
    if (move->moveSpeed == nullptr)
    {
        request.Speed = nullptr;
    }
    else
    {
        auto speed = move->moveSpeed;
        if (speed->zoomSpeedEnable)
        {
            switch (speed->zoomSpace)
            {
            case 0:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace";
                break;
            case 1:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/SpeedSpaceMillimeter";
                break;
            case 2:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace";
                break;
            default:
                break;
            }
            Zoom.x = speed->zoomSpeed;
            Speed.Zoom = &Zoom;
        }

        if (speed->panTiltSpeedEnable)
        {
            switch (speed->panTiltSpace)
            {
            case 0:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace";
                break;
            case 1:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/SpeedSpaceDegrees";
                break;
            case 2:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace";
                break;
            case 3:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocitySpaceDegrees";
                break;
            default:
                break;
            }
            PanTilt.x = speed->panSpeed;
            PanTilt.y = speed->tiltSpeed;
            Speed.PanTilt = &PanTilt;
        }
        request.Speed = &Speed;
    }

    // 发送请求并接收回复
    if (soap_call___tptz__RelativeMove(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::continuousMove(string &responseJson,
                                           const char *deviceXAddr,
                                           const char *userName,
                                           const char *password,
                                           const char *profileToken,
                                           ONVIF_PTZ_SPEED_PARAM *speed,
                                           const char *timeOutDuration)
{
    string errPrefix = "continuousMove error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__ContinuousMove request;          // 请求
    _tptz__ContinuousMoveResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;
    request.Timeout = (char *)timeOutDuration;
    tt__PTZSpeed Speed;
    Speed.Zoom = nullptr;
    Speed.PanTilt = nullptr;
    tt__Vector2D PanTilt;
    tt__Vector1D Zoom;
    if (speed == nullptr)
    {
        request.Velocity = nullptr;
    }
    else
    {
        if (speed->zoomSpeedEnable)
        {
            switch (speed->zoomSpace)
            {
            case 0:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace";
                break;
            case 1:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/SpeedSpaceMillimeter";
                break;
            case 2:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace";
                break;
            default:
                break;
            }
            Zoom.x = speed->zoomSpeed;
            Speed.Zoom = &Zoom;
        }

        if (speed->panTiltSpeedEnable)
        {
            switch (speed->panTiltSpace)
            {
            case 0:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace";
                break;
            case 1:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/SpeedSpaceDegrees";
                break;
            case 2:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace";
                break;
            case 3:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocitySpaceDegrees";
                break;

            default:
                break;
            }
            PanTilt.x = speed->panSpeed;
            PanTilt.y = speed->tiltSpeed;
            Speed.PanTilt = &PanTilt;
        }
        request.Velocity = &Speed;
    }

    // 发送请求并接收回复
    if (soap_call___tptz__ContinuousMove(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::stopMove(string &responseJson,
                                     const char *deviceXAddr,
                                     const char *userName,
                                     const char *password,
                                     const char *profileToken,
                                     bool panTilt,
                                     bool zoom)
{
    string errPrefix = "stopMove error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__Stop request;          // 请求
    _tptz__StopResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;
    request.PanTilt = &panTilt;
    request.Zoom = &zoom;

    // 发送请求并接收回复
    if (soap_call___tptz__Stop(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getPresets(string &responseJson,
                                       const char *deviceXAddr,
                                       const char *userName,
                                       const char *password,
                                       const char *profileToken)
{
    string errPrefix = "getPresets error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__GetPresets request;          // 请求
    _tptz__GetPresetsResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___tptz__GetPresets(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> presets;
    for (int i = 0; i < response.__sizePreset; i++)
    {

        json item;

        item["token"] = response.Preset[0]->token ? string(response.Preset[i]->token) : string("");
        item["name"] = response.Preset[0]->Name ? string(response.Preset[i]->Name) : string("");

        string PTZPosition = "";
        jsonOperation::parsePTZVector(PTZPosition, response.Preset[i]->PTZPosition);
        if (PTZPosition != "")
        {
            item["PTZPosition"] = json::parse(PTZPosition);
        }

        presets.push_back(item);
    }
    j["preset"] = presets;
    j["count"] = response.__sizePreset;

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::gotoHomePosition(string &responseJson,
                                             const char *deviceXAddr,
                                             const char *userName,
                                             const char *password,
                                             const char *profileToken,
                                             ONVIF_PTZ_SPEED_PARAM *speed)
{
    string errPrefix = "gotoHomePosition error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__GotoHomePosition request;          // 请求
    _tptz__GotoHomePositionResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;
    tt__PTZSpeed Speed;
    Speed.Zoom = nullptr;
    Speed.PanTilt = nullptr;
    tt__Vector2D PanTilt;
    tt__Vector1D Zoom;
    if (speed == nullptr)
    {
        request.Speed = nullptr;
    }
    else
    {
        if (speed->zoomSpeedEnable)
        {
            switch (speed->zoomSpace)
            {
            case 0:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace";
                break;
            case 1:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/SpeedSpaceMillimeter";
                break;
            case 2:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace";
                break;
            default:
                break;
            }
            Zoom.x = speed->zoomSpeed;
            Speed.Zoom = &Zoom;
        }

        if (speed->panTiltSpeedEnable)
        {
            switch (speed->panTiltSpace)
            {
            case 0:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace";
                break;
            case 1:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/SpeedSpaceDegrees";
                break;
            case 2:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace";
                break;
            case 3:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocitySpaceDegrees";
                break;

            default:
                break;
            }
            PanTilt.x = speed->panSpeed;
            PanTilt.y = speed->tiltSpeed;
            Speed.PanTilt = &PanTilt;
        }
        request.Speed = &Speed;
    }

    // 发送请求并接收回复
    if (soap_call___tptz__GotoHomePosition(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setHomePosition(string &responseJson,
                                            const char *deviceXAddr,
                                            const char *userName,
                                            const char *password,
                                            const char *profileToken)
{
    string errPrefix = "setHomePosition error";

    // 判断参数是否有效
    if (profileToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__SetHomePosition request;          // 请求
    _tptz__SetHomePositionResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;

    // 发送请求并接收回复
    if (soap_call___tptz__SetHomePosition(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::gotoPreset(string &responseJson,
                                       const char *deviceXAddr,
                                       const char *userName,
                                       const char *password,
                                       const char *profileToken,
                                       const char *presetToken,
                                       ONVIF_PTZ_SPEED_PARAM *speed)
{
    string errPrefix = "gotoPreset error";

    // 判断参数是否有效
    if (profileToken == nullptr || presetToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__GotoPreset request;          // 请求
    _tptz__GotoPresetResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;
    request.PresetToken = (char *)presetToken;
    tt__PTZSpeed Speed;
    Speed.Zoom = nullptr;
    Speed.PanTilt = nullptr;
    tt__Vector2D PanTilt;
    tt__Vector1D Zoom;
    if (speed == nullptr)
    {
        request.Speed = nullptr;
    }
    else
    {
        if (speed->zoomSpeedEnable)
        {
            switch (speed->zoomSpace)
            {
            case 0:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace";
                break;
            case 1:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/SpeedSpaceMillimeter";
                break;
            case 2:
                Zoom.space = (char *)"http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace";
                break;
            default:
                break;
            }
            Zoom.x = speed->zoomSpeed;
            Speed.Zoom = &Zoom;
        }

        if (speed->panTiltSpeedEnable)
        {
            switch (speed->panTiltSpace)
            {
            case 0:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace";
                break;
            case 1:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/SpeedSpaceDegrees";
                break;
            case 2:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace";
                break;
            case 3:
                PanTilt.space = (char *)"http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocitySpaceDegrees";
                break;

            default:
                break;
            }
            PanTilt.x = speed->panSpeed;
            PanTilt.y = speed->tiltSpeed;
            Speed.PanTilt = &PanTilt;
        }
        request.Speed = &Speed;
    }

    // 发送请求并接收回复
    if (soap_call___tptz__GotoPreset(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::setPreset(string &responseJson,
                                      const char *deviceXAddr,
                                      const char *userName,
                                      const char *password,
                                      const char *profileToken,
                                      const char *presetToken,
                                      const char *presetName)
{
    string errPrefix = "setPreset error";

    // 判断参数是否有效
    if (profileToken == nullptr || presetToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__SetPreset request;          // 请求
    _tptz__SetPresetResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;
    request.PresetToken = (char *)presetToken;
    request.PresetName = nullptr;
    if (presetName != nullptr)
    {
        request.PresetName = (char *)presetName;
    }

    // 发送请求并接收回复
    if (soap_call___tptz__SetPreset(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::addPreset(string &responseJson,
                                      const char *deviceXAddr,
                                      const char *userName,
                                      const char *password,
                                      const char *profileToken,
                                      const char *presetName)
{
    string errPrefix = "addPreset error";

    // 判断参数是否有效
    if (profileToken == nullptr || presetName == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__SetPreset request;          // 请求
    _tptz__SetPresetResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;
    request.PresetToken = nullptr;
    request.PresetName = (char *)presetName;

    // 发送请求并接收回复
    if (soap_call___tptz__SetPreset(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析返回结果到jsonStr里
    json j;
    j["presetToken"] = response.PresetToken ? string(response.PresetToken) : string("");

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::removePreset(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password,
                                         const char *profileToken,
                                         const char *presetToken)
{
    string errPrefix = "removePreset error";

    // 判断参数是否有效
    if (profileToken == nullptr || presetToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tptz__RemovePreset request;          // 请求
    _tptz__RemovePresetResponse response; // 回复

    // 设置请求参数
    request.ProfileToken = (char *)profileToken;
    request.PresetToken = (char *)presetToken;

    // 发送请求并接收回复
    if (soap_call___tptz__RemovePreset(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getRecordingSummary(string &responseJson,
                                                const char *deviceXAddr,
                                                const char *userName,
                                                const char *password)
{
    string errPrefix = "getRecordingSummary error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tse__GetRecordingSummary request;          // 请求
    _tse__GetRecordingSummaryResponse response; // 回复

    // 发送请求并接收回复
    if (soap_call___tse__GetRecordingSummary(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    if (response.Summary != nullptr)
    {
        j["dataFrom"] = string(onvifToolUtils::time_tToDateTime(response.Summary->DataFrom));
        j["dataUntil"] = string(onvifToolUtils::time_tToDateTime(response.Summary->DataUntil));
        j["numberRecordings"] = to_string(response.Summary->NumberRecordings);
    }

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::findRecordings(string &responseJson,
                                           const char *deviceXAddr,
                                           const char *userName,
                                           const char *password,
                                           ONVIF_FIND_RECORDINGS_PARAM *param)
{
    string errPrefix = "findRecordings error";

    // 判断参数是否有效
    if (param == nullptr ||
        (param->includeRecordingsTokenSize > 0 && param->includeRecordingsToken == nullptr) ||
        (param->includeSourcesTokenSize > 0 && param->includeSourcesToken == nullptr))
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tse__FindRecordings request;          // 请求
    _tse__FindRecordingsResponse response; // 回复

    // 设置请求参数
    tt__SearchScope Scope;
    Scope.__sizeIncludedSources = param->includeSourcesTokenSize;
    Scope.__sizeIncludedRecordings = param->includeRecordingsTokenSize;
    Scope.IncludedSources = nullptr;
    Scope.IncludedRecordings = nullptr;

    if (Scope.__sizeIncludedSources != 0)
    {
        Scope.IncludedSources = new tt__SourceReference *[Scope.__sizeIncludedSources];
        for (int i = 0; i < Scope.__sizeIncludedSources; i++)
        {
            Scope.IncludedSources[i] = new tt__SourceReference;
            Scope.IncludedSources[i]->Token = param->includeSourcesToken[i];
            if (param->includeSourcesType != nullptr)
            {
                if (param->includeSourcesType[i] == nullptr)
                {
                    Scope.IncludedSources[i]->Type = nullptr;
                    continue;
                }
                switch (*param->includeSourcesType[i])
                {
                case 0:
                    Scope.IncludedSources[i]->Type = (char *)"http://www.onvif.org/ver10/schema/Profile";
                    break;
                case 1:
                    Scope.IncludedSources[i]->Type = (char *)"http://www.onvif.org/ver10/schema/Receiver";
                    break;

                default:
                    break;
                }
            }
        }
    }

    if (Scope.__sizeIncludedRecordings != 0)
    {
        Scope.IncludedRecordings = param->includeRecordingsToken;
    }

    Scope.RecordingInformationFilter = param->recordingInformationFilter;
    Scope.Extension = nullptr;

    request.Scope = &Scope;
    request.MaxMatches = param->maxMatches;
    request.KeepAliveTime = param->keepAliveTime;

    // 发送请求并接收回复
    if (soap_call___tse__FindRecordings(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        if (Scope.IncludedSources != nullptr)
        {
            for (int i = 0; i < Scope.__sizeIncludedSources; i++)
            {
                delete Scope.IncludedSources[i];
            }
            delete Scope.IncludedSources;
            Scope.IncludedSources = nullptr;
        }
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    j["searchToken"] = response.SearchToken ? string(response.SearchToken) : string("");

    responseJson = j.dump();
    if (Scope.IncludedSources != nullptr)
    {
        for (int i = 0; i < Scope.__sizeIncludedSources; i++)
        {
            delete Scope.IncludedSources[i];
        }
        delete Scope.IncludedSources;
        Scope.IncludedSources = nullptr;
    }
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getRecordingInformation(string &responseJson,
                                                    const char *deviceXAddr,
                                                    const char *userName,
                                                    const char *password,
                                                    const char *recordingToken)
{
    string errPrefix = "getRecordingInformation error";

    // 判断参数是否有效
    if (recordingToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tse__GetRecordingInformation request;          // 请求
    _tse__GetRecordingInformationResponse response; // 回复

    // 设置请求参数
    request.RecordingToken = (char *)recordingToken;

    // 发送请求并接收回复
    if (soap_call___tse__GetRecordingInformation(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    string jsonStr;

    if (auto err = jsonOperation::parseRecordingInformation(jsonStr, response.RecordingInformation); err)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, *err);
    }

    responseJson = jsonStr;
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getRecordingSearchResults(string &responseJson,
                                                      const char *deviceXAddr,
                                                      const char *userName,
                                                      const char *password,
                                                      const char *searchToken,
                                                      const int *minResults,
                                                      const int *maxResults,
                                                      const char *waitDuration)
{
    string errPrefix = "getRecordingSearchResults error";

    // 判断参数是否有效
    if (searchToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tse__GetRecordingSearchResults request;          // 请求
    _tse__GetRecordingSearchResultsResponse response; // 回复

    // 设置请求参数
    request.SearchToken = (char *)searchToken;
    request.MinResults = (int *)minResults;
    request.MaxResults = (int *)maxResults;
    request.WaitTime = (char *)waitDuration;

    // 发送请求并接收回复
    if (soap_call___tse__GetRecordingSearchResults(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    vector<json> recordingInformations;
    for (int i = 0; i < response.ResultList->__sizeRecordingInformation; i++)
    {
        string jsonStr;
        if (auto err = jsonOperation::parseRecordingInformation(jsonStr, response.ResultList->RecordingInformation[i]); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(jsonStr);
        recordingInformations.push_back(item);
    }
    j["recordingInformation"] = recordingInformations;
    switch (response.ResultList->SearchState)
    {
    case tt__SearchState__Completed:
        j["searchState"] = string("completed");
        break;
    case tt__SearchState__Queued:
        j["searchState"] = string("queued");
        break;
    case tt__SearchState__Searching:
        j["searchState"] = string("searching");
        break;
    case tt__SearchState__Unknown:
        j["searchState"] = string("unknown");
        break;

    default:
        break;
    }

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::endSearch(string &responseJson,
                                      const char *deviceXAddr,
                                      const char *userName,
                                      const char *password,
                                      const char *searchToken)
{
    string errPrefix = "endSearch error";

    // 判断参数是否有效
    if (searchToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _tse__EndSearch request;          // 请求
    _tse__EndSearchResponse response; // 回复

    // 设置请求参数
    request.SearchToken = (char *)searchToken;

    // 发送请求并接收回复
    if (soap_call___tse__EndSearch(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;

    j["endPoint"] = string(ctime(&response.Endpoint));

    responseJson = j.dump();
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::getReplayUri(string &responseJson,
                                         const char *deviceXAddr,
                                         const char *userName,
                                         const char *password,
                                         const char *recordingToken,
                                         ONVIF_STREAM_SETUP_PARAM *streamSetup)
{
    string errPrefix = "getReplayUri error";

    // 判断参数是否有效
    if (recordingToken == nullptr || streamSetup == nullptr || streamSetup->streamType > 1 || streamSetup->transport.protocolsName > 3)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _trp__GetReplayUri request;          // 请求
    _trp__GetReplayUriResponse response; // 回复

    // 定义一个函数用来递归生成tt__Transport
    auto fun = [](tt__Transport *transport, ONVIF_TRANSPORT_PROTOCOL *param, auto &&self) -> void
    {
        switch (param->protocolsName)
        {
        case 0:
            transport->Protocol = tt__TransportProtocol__UDP;
            break;
        case 1:
            transport->Protocol = tt__TransportProtocol__TCP;
            break;
        case 2:
            transport->Protocol = tt__TransportProtocol__RTSP;
            break;
        case 3:
            transport->Protocol = tt__TransportProtocol__HTTP;
            break;
        default:
            break;
        }

        transport->Tunnel = nullptr;
        if (param->tunnel == nullptr)
        {
            return;
        }

        transport->Tunnel = new tt__Transport;
        self(transport->Tunnel, param->tunnel, self);
    };

    // 定义一个函数用来释放tt__Transport
    auto deleteFun = [](tt__Transport *transport, auto &&self) -> void
    {
        if (transport == nullptr)
        {
            return;
        }

        if (transport->Tunnel != nullptr)
        {
            self(transport->Tunnel, self);
            transport->Tunnel = nullptr;
        }

        delete transport;
        transport = nullptr;
    };

    // 设置请求参数
    request.RecordingToken = (char *)recordingToken;

    tt__StreamSetup streamSetup_;

    switch (streamSetup->streamType)
    {
    case 0:
        streamSetup_.Stream = tt__StreamType__RTP_Unicast;
        break;
    case 1:
        streamSetup_.Stream = tt__StreamType__RTP_Multicast;
        break;
    default:
        break;
    }

    tt__Transport *transport = new tt__Transport;
    fun(transport, &streamSetup->transport, fun);

    streamSetup_.Transport = transport;
    request.StreamSetup = &streamSetup_;

    // 发送请求并接收回复
    if (soap_call___trp__GetReplayUri(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteFun(transport, deleteFun);
        deleteSoap(soapPtr);
        return err;
    }

    // 解析回复到jsonStr里
    json j;
    j["uri"] = response.Uri ? string(response.Uri) : string("");

    responseJson = j.dump();
    deleteFun(transport, deleteFun);
    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::focusMove(string &responseJson,
                                      const char *deviceXAddr,
                                      const char *userName,
                                      const char *password,
                                      const char *videoSourceToken,
                                      ONVIF_FOCUS_MOVE_PARAM *moveParam)
{
    string errPrefix = "focusMove error";

    // 判断参数是否有效
    if (videoSourceToken == nullptr || moveParam == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns2__FocusMove request;          // 请求
    _ns2__FocusMoveResponse response; // 回复

    // 设置请求参数
    request.VideoSource = (char *)videoSourceToken;
    request.Timeout = (char *)moveParam->timeOut;
    switch (moveParam->direction)
    {
    case 0:
        request.Direction = ns2__FocusDirection__Auto;
        break;
    case 1:
        request.Direction = ns2__FocusDirection__Near;
        break;
    case 2:
        request.Direction = ns2__FocusDirection__Far;
        break;

    default:
        request.Direction = ns2__FocusDirection__Auto;
        break;
    }

    // 发送请求并接收回复
    if (soap_call___ns2__FocusMove(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::stopFocusMove(string &responseJson,
                                          const char *deviceXAddr,
                                          const char *userName,
                                          const char *password,
                                          const char *videoSourceToken)
{
    string errPrefix = "stopFocusMove error";

    // 判断参数是否有效
    if (videoSourceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _ns2__Stop request;          // 请求
    _ns2__StopResponse response; // 回复

    // 设置请求参数
    request.VideoSource = (char *)videoSourceToken;

    // 发送请求并接收回复
    if (soap_call___ns2__Stop(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::focusMove_Imaging(string &responseJson,
                                              const char *deviceXAddr,
                                              const char *userName,
                                              const char *password,
                                              const char *videoSourceToken,
                                              float focusSpeed)
{
    string errPrefix = "focusMove_Imaging error";

    // 判断参数是否有效
    if (videoSourceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _timg__Move request;          // 请求
    _timg__MoveResponse response; // 回复

    // 设置请求参数
    request.VideoSourceToken = (char *)videoSourceToken;

    tt__FocusMove focusMove;
    focusMove.Absolute = nullptr;
    focusMove.Relative = nullptr;

    tt__ContinuousFocus continuousFocus;
    continuousFocus.Speed = focusSpeed;
    focusMove.Continuous = &continuousFocus;

    request.Focus = &focusMove;

    // 发送请求并接收回复
    if (soap_call___timg__Move(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

optional<string> onvifTool::stopFocusMove_Imaging(string &responseJson,
                                                  const char *deviceXAddr,
                                                  const char *userName,
                                                  const char *password,
                                                  const char *videoSourceToken)
{
    string errPrefix = "stopFocusMove_Imaging error";

    // 判断参数是否有效
    if (videoSourceToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 设置鉴权消息
    if (userName != nullptr)
    {
        if (auto err = setAuthInfo(soapPtr, userName, password); err)
        {
            deleteSoap(soapPtr);
            return makeErrorStr(errPrefix, *err);
        }
    }

    _timg__Stop request;          // 请求
    _timg__StopResponse response; // 回复

    // 设置请求参数
    request.VideoSourceToken = (char *)videoSourceToken;

    // 发送请求并接收回复
    if (soap_call___timg__Stop(soapPtr, deviceXAddr, nullptr, &request, response) != 0)
    {
        string err = printError(soapPtr, errPrefix);
        deleteSoap(soapPtr);
        return err;
    }

    deleteSoap(soapPtr);
    return nullopt;
}

// 获取网卡ip列表
optional<string> onvifTool::getIpList()
{
#ifdef WIN32
    WSAData data;
    if (WSAStartup(MAKEWORD(1, 1), &data) != 0)
    {
        return "getIpList WSAStartup fail\n";
    }

    char host[255];
    if (gethostname(host, sizeof(host)) != 0)
    {
        return "getIpList could not get host name\n";
    }

    struct hostent *p = gethostbyname(host);
    if (p == nullptr)
    {
        return "getIpList could not get host by name\n";
    }
    else
    {
        // 本机IP:利用循环,输出本机所有IP
        for (int i = 0; p->h_addr_list[i] != 0; i++)
        {
            struct in_addr in;
            memcpy(&in, p->h_addr_list[i], sizeof(struct in_addr));
            ipList.push_back(string(inet_ntoa(in)));
            string message = "第" + to_string((i + 1)) + "个网卡的ip地址为:" + ipList[i];
            log(message, LOG_INFO);
        }
    }

    WSACleanup();

#else
    struct ifaddrs *ifAddrStruct = NULL;
    struct ifaddrs *ifa = NULL;
    void *tmpAddrPtr = NULL;

    getifaddrs(&ifAddrStruct);

    int i = 0;
    for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next, i++)
    {
        if (!ifa->ifa_addr)
        {
            continue;
        }
        // ipv4地址
        if (ifa->ifa_addr->sa_family == AF_INET && string(ifa->ifa_name) != "lo")
        {
            tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
            char addressBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
            ipList.push_back(string(addressBuffer));
            string message = string(ifa->ifa_name) + " 的ip地址为:" + string(addressBuffer);
            log(message, LOG_INFO);
        }
    }
    if (ifAddrStruct != NULL)
    {
        freeifaddrs(ifAddrStruct);
    }
#endif

    return nullopt;
}

// 创建一个soap
soap *onvifTool::newSoap()
{
    soap *soapPtr = nullptr;
    soapPtr = soap_new();
    if (soapPtr == nullptr)
    {
        log("newSoap err", LOG_ERROR);
        return nullptr;
    }

    // 设置soap的namespace
    soap_set_namespaces(soapPtr, namespaces);

    // 设置超时时间
    soapPtr->recv_timeout = timeOut;
    soapPtr->send_timeout = timeOut;
    soapPtr->connect_timeout = timeOut;

    // 参考https://www.genivia.com/dev.html#client-c
#if defined(__linux__) || defined(__linux)
    soapPtr->socket_flags = MSG_NOSIGNAL;
#endif

    // 设置编码格式
    soap_set_mode(soapPtr, SOAP_C_UTFSTRING);

    // 使用https的关键代码
    soap_register_plugin(soapPtr, soap_wsse);
    if (soap_ssl_client_context(soapPtr, SOAP_SSL_NO_AUTHENTICATION, NULL, NULL, NULL, NULL, NULL) != 0)
    {
        auto err = printError(soapPtr, "soap_ssl_client_context error");
        log(makeErrorStr("newSoap err", err), LOG_WARNING);
    }

    return soapPtr;
}

void onvifTool::deleteSoap(soap *soapPtr)
{
    soap_destroy(soapPtr);
    soap_end(soapPtr);
    soap_free(soapPtr);
}

string onvifTool::printError(soap *soapPtr, string errorPrefix)
{
    string message;
    if (soapPtr->error == -1)
    {
        this->timeOut += 5;
        message = errorPrefix +
                  ": unexpected error, soap error: -1, the server may not respond;" +
                  " try again or try setting a longer TimeOut to resolve the issue";
    }
    else
    {

        message = errorPrefix +
                  ": soap error: " + to_string(soapPtr->error) +
                  ", faultcode: " + string(soap_faultcode(soapPtr) ? *soap_faultcode(soapPtr) ? *soap_faultcode(soapPtr) : "" : "") +
                  ", subcode: " + string(soap_fault_subcode(soapPtr) ? soap_fault_subcode(soapPtr) : "") +
                  ", faultstring: " + string(soap_fault_string(soapPtr) ? soap_fault_string(soapPtr) : "") +
                  ", detail: " + string(soap_fault_detail(soapPtr) ? soap_fault_detail(soapPtr) : "");
    }
    return string(message);
}

void onvifTool::log(string message, int logLevel)
{
    if (cb_ == nullptr)
    {
        utils.log(message, logLevel);
        return;
    }
    string newMessage = string("[onvifTool]\t") + message;
    cb_(newMessage, logLevel, logUserData);
}

string onvifTool::makeErrorStr(string errorPrefix, string err)
{
    return errorPrefix + ": " + err;
}

optional<string> onvifTool::setAuthInfo(soap *soapPtr, const char *username, const char *password)
{
    int result = 0;

    if (username == nullptr || password == nullptr)
    {
        return "setAuthInfo fail: param err: username is null or password is null";
    }

    result = soap_wsse_add_UsernameTokenDigest(soapPtr, NULL, username, password);
    if (result != 0)
    {
        return "setAuthInfo fail: call soap_wsse_add_UsernameTokenDigest fail";
    }
    return nullopt;
}

optional<string> onvifTool::listenHello(listenCB cb, void *pUserData, const char *interfaceAddr)
{
    string errPrefix = "listenHello error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 指定创建UDP模式
    soapPtr->imode = SOAP_IO_UDP | SOAP_IO_FLUSH;
    soapPtr->mode = soapPtr->imode;
    soapPtr->omode = SOAP_IO_UDP | SOAP_IO_FLUSH;

    // 允许socket重用IP/port
    soapPtr->bind_flags = SO_REUSEADDR;

    // 开启socket
    if (!soap_valid_socket(soap_bind(soapPtr, NULL, 3702, 10)))
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "bind fail");
    }

    // 设置监听多播地址的网卡
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(MUTICAST_ADDR);
    mreq.imr_interface.s_addr = inet_addr(interfaceAddr);
#ifdef WIN32
    if (setsockopt(soapPtr->master, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
    {
        return makeErrorStr(errPrefix, "bind interface fail");
    }
#else
    if (setsockopt(soapPtr->master, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
    {
        return makeErrorStr(errPrefix, "bind interface fail");
    }
#endif

    // 使用新设置好的socket来监听
    soapPtr->recvsk = soapPtr->master;

    // 开始监听
    listenHelloFlag = 0;
    thread t(&onvifTool::listenHelloThread, this, soapPtr, cb, pUserData);
    t.detach();

    return nullopt;
}

optional<string> onvifTool::listenBye(listenCB cb, void *pUserData, const char *interfaceAddr)
{
    string errPrefix = "listenBye error";

    // 新建soap对象
    auto soapPtr = newSoap();
    if (soapPtr == nullptr)
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "newSoap error");
    }

    // 指定创建UDP模式
    soapPtr->imode = SOAP_IO_UDP | SOAP_IO_FLUSH;
    soapPtr->mode = soapPtr->imode;
    soapPtr->omode = SOAP_IO_UDP | SOAP_IO_FLUSH;

    // 允许socket重用IP/port
    soapPtr->bind_flags = SO_REUSEADDR;

    // 开启socket
    if (!soap_valid_socket(soap_bind(soapPtr, NULL, 3702, 10)))
    {
        deleteSoap(soapPtr);
        return makeErrorStr(errPrefix, "bind fail");
    }

    // 设置监听多播地址的网卡
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(MUTICAST_ADDR);
    mreq.imr_interface.s_addr = inet_addr(interfaceAddr);
#ifdef WIN32
    if (setsockopt(soapPtr->master, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
    {
        return makeErrorStr(errPrefix, "bind interface fail");
    }
#else
    if (setsockopt(soapPtr->master, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
    {
        return makeErrorStr(errPrefix, "bind interface fail");
    }
#endif

    // 使用新设置好的socket来监听
    soapPtr->recvsk = soapPtr->master;

    // 开始监听
    listenByeFlag = 0;
    thread t(&onvifTool::listenByeThread, this, soapPtr, cb, pUserData);
    t.detach();

    return nullopt;
}

void onvifTool::listenHelloThread(soap *soapPtr, listenCB cb, void *pUserData)
{
    do
    {
        __wsdd__Hello response;
        if (soap_recv___wsdd__Hello(soapPtr, &response) != 0)
        {
            continue;
        }
        else
        {
            if (response.wsdd__Hello == nullptr)
            {
                continue;
            }
            json device;
            device["serviceAddress"] = response.wsdd__Hello->XAddrs ? string(response.wsdd__Hello->XAddrs) : string("");
            device["types"] = response.wsdd__Hello->Types ? string(response.wsdd__Hello->Types) : string("");
            device["scopes"] = response.wsdd__Hello->Scopes ? (response.wsdd__Hello->Scopes->__item ? string(response.wsdd__Hello->Scopes->__item) : string("")) : string("");
            device["endPointAddress"] = response.wsdd__Hello->wsa__EndpointReference.Address ? string(response.wsdd__Hello->wsa__EndpointReference.Address) : string("");
            cb(device.dump(), pUserData);
        }
    } while (listenHelloFlag != 1);
    deleteSoap(soapPtr);
}

void onvifTool::listenByeThread(soap *soapPtr, listenCB cb, void *pUserData)
{
    do
    {
        __wsdd__Bye response;
        if (soap_recv___wsdd__Bye(soapPtr, &response) != 0)
        {
            continue;
        }
        else
        {
            if (response.wsdd__Bye == nullptr)
            {
                continue;
            }
            json device;
            device["serviceAddress"] = response.wsdd__Bye->XAddrs ? string(response.wsdd__Bye->XAddrs) : string("");
            device["types"] = response.wsdd__Bye->Types ? string(response.wsdd__Bye->Types) : string("");
            device["scopes"] = response.wsdd__Bye->Scopes ? (response.wsdd__Bye->Scopes->__item ? string(response.wsdd__Bye->Scopes->__item) : string("")) : string("");
            device["endPointAddress"] = response.wsdd__Bye->wsa__EndpointReference.Address ? string(response.wsdd__Bye->wsa__EndpointReference.Address) : string("");
            cb(device.dump(), pUserData);
        }
    } while (listenByeFlag != 1);
    deleteSoap(soapPtr);
}

void onvifTool::buildGetServiceCapabilitiesJsonStr(string &responseJson, _tds__GetServiceCapabilitiesResponse &response)
{
    json j;
    if (response.Capabilities->Network != nullptr)
    {
        j["network"]["ipFilter"] = response.Capabilities->Network->IPFilter
                                       ? (*(response.Capabilities->Network->IPFilter)
                                              ? "true"
                                              : "false")
                                       : "";
        j["network"]["zeroConfiguration"] = response.Capabilities->Network->ZeroConfiguration
                                                ? (*(response.Capabilities->Network->ZeroConfiguration)
                                                       ? "true"
                                                       : "false")
                                                : "";
        j["network"]["ipVersion6"] = response.Capabilities->Network->IPVersion6
                                         ? (*(response.Capabilities->Network->IPVersion6)
                                                ? "true"
                                                : "false")
                                         : "";
        j["network"]["dynDNS"] = response.Capabilities->Network->DynDNS
                                     ? (*(response.Capabilities->Network->DynDNS)
                                            ? "true"
                                            : "false")
                                     : "";
        j["network"]["dot11Configuration"] = response.Capabilities->Network->Dot11Configuration
                                                 ? (*(response.Capabilities->Network->Dot11Configuration)
                                                        ? "true"
                                                        : "false")
                                                 : "";
        j["network"]["dot1XConfigurations"] = response.Capabilities->Network->Dot1XConfigurations
                                                  ? std::to_string(*(response.Capabilities->Network->Dot1XConfigurations))
                                                  : "";
        j["network"]["hostnameFromDHCP"] = response.Capabilities->Network->HostnameFromDHCP
                                               ? (*(response.Capabilities->Network->HostnameFromDHCP)
                                                      ? "true"
                                                      : "false")
                                               : "";
        j["network"]["NTP"] = response.Capabilities->Network->NTP
                                  ? std::to_string(*(response.Capabilities->Network->NTP))
                                  : "";
        j["network"]["DHCPv6"] = response.Capabilities->Network->DHCPv6
                                     ? (*(response.Capabilities->Network->DHCPv6)
                                            ? "true"
                                            : "false")
                                     : "";
    }

    if (response.Capabilities->Security != nullptr)
    {
        j["security"]["TLS1.0"] = response.Capabilities->Security->TLS1_x002e0
                                      ? (*(response.Capabilities->Security->TLS1_x002e0)
                                             ? "true"
                                             : "false")
                                      : "";
        j["security"]["TLS1.1"] = response.Capabilities->Security->TLS1_x002e1
                                      ? (*(response.Capabilities->Security->TLS1_x002e1)
                                             ? "true"
                                             : "false")
                                      : "";
        j["security"]["TLS1.2"] = response.Capabilities->Security->TLS1_x002e2
                                      ? (*(response.Capabilities->Security->TLS1_x002e2)
                                             ? "true"
                                             : "false")
                                      : "";
        j["security"]["onboardKeyGeneration"] = response.Capabilities->Security->OnboardKeyGeneration
                                                    ? (*(response.Capabilities->Security->OnboardKeyGeneration)
                                                           ? "true"
                                                           : "false")
                                                    : "";
        j["security"]["accessPolicyConfig"] = response.Capabilities->Security->AccessPolicyConfig
                                                  ? (*(response.Capabilities->Security->AccessPolicyConfig)
                                                         ? "true"
                                                         : "false")
                                                  : "";
        j["security"]["defaultAccessPolicy"] = response.Capabilities->Security->DefaultAccessPolicy
                                                   ? (*(response.Capabilities->Security->DefaultAccessPolicy)
                                                          ? "true"
                                                          : "false")
                                                   : "";
        j["security"]["dot1X"] = response.Capabilities->Security->Dot1X
                                     ? (*(response.Capabilities->Security->Dot1X)
                                            ? "true"
                                            : "false")
                                     : "";
        j["security"]["remoteUserHandling"] = response.Capabilities->Security->RemoteUserHandling
                                                  ? (*(response.Capabilities->Security->RemoteUserHandling)
                                                         ? "true"
                                                         : "false")
                                                  : "";
        j["security"]["X.509Token"] = response.Capabilities->Security->X_x002e509Token
                                          ? (*(response.Capabilities->Security->X_x002e509Token)
                                                 ? "true"
                                                 : "false")
                                          : "";
        j["security"]["SAMLToken"] = response.Capabilities->Security->SAMLToken
                                         ? (*(response.Capabilities->Security->SAMLToken)
                                                ? "true"
                                                : "false")
                                         : "";
        j["security"]["kerberosToken"] = response.Capabilities->Security->KerberosToken
                                             ? (*(response.Capabilities->Security->KerberosToken)
                                                    ? "true"
                                                    : "false")
                                             : "";
        j["security"]["usernameToken"] = response.Capabilities->Security->UsernameToken
                                             ? (*(response.Capabilities->Security->UsernameToken)
                                                    ? "true"
                                                    : "false")
                                             : "";
        j["security"]["HttpDigest"] = response.Capabilities->Security->HttpDigest
                                          ? (*(response.Capabilities->Security->HttpDigest)
                                                 ? "true"
                                                 : "false")
                                          : "";
        j["security"]["RELToken"] = response.Capabilities->Security->RELToken
                                        ? (*(response.Capabilities->Security->RELToken)
                                               ? "true"
                                               : "false")
                                        : "";
        j["security"]["supportedEAPMethods"] = response.Capabilities->Security->SupportedEAPMethods
                                                   ? string(response.Capabilities->Security->SupportedEAPMethods)
                                                   : "";
        j["security"]["maxUsers"] = response.Capabilities->Security->MaxUsers
                                        ? std::to_string(*(response.Capabilities->Security->MaxUsers))
                                        : "";
        j["security"]["maxUserNameLength"] = response.Capabilities->Security->MaxUserNameLength
                                                 ? std::to_string(*(response.Capabilities->Security->MaxUserNameLength))
                                                 : "";
        j["security"]["maxPasswordLength"] = response.Capabilities->Security->MaxPasswordLength
                                                 ? std::to_string(*(response.Capabilities->Security->MaxPasswordLength))
                                                 : "";
        j["security"]["securityPolicies"] = response.Capabilities->Security->SecurityPolicies
                                                ? string(response.Capabilities->Security->SecurityPolicies)
                                                : "";
        j["security"]["maxPasswordHistory"] = response.Capabilities->Security->MaxPasswordHistory
                                                  ? std::to_string(*(response.Capabilities->Security->MaxPasswordHistory))
                                                  : "";
        j["security"]["hashingAlgorithms"] = response.Capabilities->Security->HashingAlgorithms
                                                 ? string(response.Capabilities->Security->HashingAlgorithms)
                                                 : "";
    }

    if (response.Capabilities->System != nullptr)
    {
        j["system"]["discoveryResolve"] = response.Capabilities->System->DiscoveryResolve
                                              ? (*(response.Capabilities->System->DiscoveryResolve)
                                                     ? "true"
                                                     : "false")
                                              : "";
        j["system"]["discoveryBye"] = response.Capabilities->System->DiscoveryBye
                                          ? (*(response.Capabilities->System->DiscoveryBye)
                                                 ? "true"
                                                 : "false")
                                          : "";
        j["system"]["remoteDiscovery"] = response.Capabilities->System->RemoteDiscovery
                                             ? (*(response.Capabilities->System->RemoteDiscovery)
                                                    ? "true"
                                                    : "false")
                                             : "";
        j["system"]["systemBackup"] = response.Capabilities->System->SystemBackup
                                          ? (*(response.Capabilities->System->SystemBackup)
                                                 ? "true"
                                                 : "false")
                                          : "";
        j["system"]["systemLogging"] = response.Capabilities->System->SystemLogging
                                           ? (*(response.Capabilities->System->SystemLogging)
                                                  ? "true"
                                                  : "false")
                                           : "";
        j["system"]["firmwareUpgrade"] = response.Capabilities->System->FirmwareUpgrade
                                             ? (*(response.Capabilities->System->FirmwareUpgrade)
                                                    ? "true"
                                                    : "false")
                                             : "";
        j["system"]["HttpFirmwareUpgrade"] = response.Capabilities->System->HttpFirmwareUpgrade
                                                 ? (*(response.Capabilities->System->HttpFirmwareUpgrade)
                                                        ? "true"
                                                        : "false")
                                                 : "";
        j["system"]["HttpSystemBackup"] = response.Capabilities->System->HttpSystemBackup
                                              ? (*(response.Capabilities->System->HttpSystemBackup)
                                                     ? "true"
                                                     : "false")
                                              : "";
        j["system"]["HttpSystemLogging"] = response.Capabilities->System->HttpSystemLogging
                                               ? (*(response.Capabilities->System->HttpSystemLogging)
                                                      ? "true"
                                                      : "false")
                                               : "";
        j["system"]["HttpSupportInformation"] = response.Capabilities->System->HttpSupportInformation
                                                    ? (*(response.Capabilities->System->HttpSupportInformation)
                                                           ? "true"
                                                           : "false")
                                                    : "";
        j["system"]["storageConfiguration"] = response.Capabilities->System->StorageConfiguration
                                                  ? (*(response.Capabilities->System->StorageConfiguration)
                                                         ? "true"
                                                         : "false")
                                                  : "";
        j["system"]["maxStorageConfigurations"] = response.Capabilities->System->MaxStorageConfigurations
                                                      ? std::to_string(*(response.Capabilities->System->MaxStorageConfigurations))
                                                      : "";
        j["system"]["geoLocationEntries"] = response.Capabilities->System->GeoLocationEntries
                                                ? std::to_string(*(response.Capabilities->System->GeoLocationEntries))
                                                : "";
        j["system"]["autoGeo"] = response.Capabilities->System->AutoGeo
                                     ? string(response.Capabilities->System->AutoGeo)
                                     : "";
        j["system"]["storageTypesSupported"] = response.Capabilities->System->StorageTypesSupported
                                                   ? string(response.Capabilities->System->StorageTypesSupported)
                                                   : "";
        j["system"]["discoveryNotSupported"] = response.Capabilities->System->DiscoveryNotSupported
                                                   ? (*(response.Capabilities->System->DiscoveryNotSupported)
                                                          ? "true"
                                                          : "false")
                                                   : "";
        j["system"]["networkConfigNotSupported"] = response.Capabilities->System->NetworkConfigNotSupported
                                                       ? (*(response.Capabilities->System->NetworkConfigNotSupported)
                                                              ? "true"
                                                              : "false")
                                                       : "";
        j["system"]["userConfigNotSupported"] = response.Capabilities->System->UserConfigNotSupported
                                                    ? (*(response.Capabilities->System->UserConfigNotSupported)
                                                           ? "true"
                                                           : "false")
                                                    : "";
        j["system"]["addons"] = response.Capabilities->System->Addons
                                    ? string(response.Capabilities->System->Addons)
                                    : "";
    }

    if (response.Capabilities->Misc != nullptr)
    {
        j["misc"]["auxiliaryCommands"] = response.Capabilities->Misc->AuxiliaryCommands
                                             ? string(response.Capabilities->Misc->AuxiliaryCommands)
                                             : "";
    }

    responseJson = j.dump();
}
